• 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
    ", l, cnt(l, l));
        }
    
        return 0;
    }
    AC Code
  • 相关阅读:
    uniapp
    vue -element admin 修改request,headers添加参数
    uniapp
    css
    uniapp
    uniapp
    vue
    vue
    vue -element 修复select下拉框在移动端需要点击两次才能选中的问题
    vue
  • 原文地址:https://www.cnblogs.com/Gaomez/p/14188799.html
Copyright © 2020-2023  润新知