AcWing 秦腾与教学评估

第一次在一个OJ上发了篇题解,没想到他们没有题解审核机制,直接就出现在题解区了.

https://www.acwing.com/solution/content/27658/

那里的markdown在这里无效,我调了一下再发到这里保存一下.

 

二分
时间复杂度 O(nlogn)
蓝书而来.
本题重点在于满足条件的位置只会不存在或者有且仅有一个,而这个点有一个特殊性质:人数是奇数.
设想:在连续的一段位置上,如果每个位置上的人数加起来为偶数,那么这一段里面不可能存在一个奇数.
如果人数加起来为奇数,那么唯一一个人数为奇数的位置必然在这一段上,利用这个特性可以二分求解.
注意对一段位置上的人数统计是可以写出O(n)方法的,复杂度太高了会TLE.具体实现请结合代码注释理解.
另外,不开long long见祖宗.

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

int T, n;
struct S{
    long long s, d, e;
}t[200010];

long long cnt(long long l, long long r){                // 统计区间[l, r]上的人数并返回
    long long ct = 0;
    long long begin, end;                               // 我们要统计的区间和输入数据的每一个区间会出现包含,被包含,交集为空等各种情况,需要对这些情况判断一下并找出等价的[begin, end]区间来处理,也就是说把原来的s,d,e转化为等价的begin,d,end
    for(int i = 1; i <= n; i++){                        // 对每一个区间依次处理
        long long s = t[i].s, e = t[i].e, d = t[i].d;   // 只是换一个方便的变量名
        if(e < l || s > r) continue;                    // 区间没有交集,跳过
        if(l <= s) begin = s;                           // s在[l,r]之内,则以s为起始点
        else {                                          // s < l,那么需要找到最小的k,使得s+k*d>=l,并以s+k*d为起始点
            long long k = (l - s - 1) / d + 1;          // 由s+k*d>=l得k>=(l-s)/d,稍微思考一下就发现我们需要对右式向上取整,想要对N/M向上取整,表达式为(N-1)/M +1
            begin = s + k * d;
        }
        end = min(r, e);                                // 这里对end的处理是显然的
        if(end - begin < 0) continue;
        ct += (end - begin) / d + 1;                    // 注意当end与bgin相等时人数一定是1
    }
    return ct;
}

int main(){
    scanf("%d", &T);
    while(T--){
        scanf("%d", &n);
        for(int i = 1; i <= n; i++) scanf("%lld%lld%lld", &t[i].s, &t[i].e, &t[i].d);
        long long l = 0, r = 2147483648LL;   // 注意有一个数据点刚好是int最大值,这里再加一保险一下
        bool bad = true;
        while(l < r && l >= 0){
            long long mid = l + r >> 1;
            if(cnt(l, mid) & 1) r = mid, bad = false;
            else l = mid + 1;
        }
        if(bad) puts("Poor QIN Teng:(");
        else printf("%lld %lld\n", l, cnt(l, l));
    }

    return 0;
}
AC Code

 

posted @ 2020-12-25 20:33  goverclock  阅读(125)  评论(0编辑  收藏  举报