zoukankan      html  css  js  c++  java
  • 【二分单个位置 前缀和】 防线

    传送门

    题意

    一维的防线,有(n)组防具,每组防具通过(s、e、d)来描述,即(s,s+d,s+2d dots , s+kd leq e , s+(k+1)d>e),如果某个位置上防具的个数是偶数个这个防线就是没有破绽的,0也是偶数,有奇数个位置有防具就是破绽,整条防线最多只有一个位置上有破绽,如果有破绽输出破绽位置和这个位置上的防具数量,否则的话输出("There's; no; weakness"),一共有(t)组测试数据.

    数据范围

    防具的总数不超过(10^{8})
    (0<= s_{i}、k_{i}、d_{i} <= 2^{31}-1)
    (n<=200000)

    题解

    通过前缀和来使具有单调性,奇数最多只有一个,所以前缀和一定为奇数,具有了单调性就可以二分位置,当前前缀和为偶则左边一定全是偶,如果存在奇数的位置一定在右半区间
    (O(n))时间求出前缀和,二分的位置是(mid),枚举每一个等差数列,如果(sleq mid)则存在交集,共同区间为([s,min(e,mid) ]),则该区间中包含这个数列的个数为

    • (leftlfloorfrac{(min (e, mid)-S)}{d} ight floor +1)

    Code

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define rep(i,a,n) for(int i=a;i<n;i++)
    const int N=2e5+10;
    ll n;
    struct node
    {
        ll s,e,d;
    }a[N];
    ll get(ll mid)
    {
        ll ans=0;
        rep(i,1,n+1)
            if(a[i].s<=mid)
                ans+=(min(mid,a[i].e)-a[i].s)/a[i].d+1;
        return ans;
    }
    void solve()
    {
        cin >> n;
        rep(i,1,n+1)
            cin >> a[i].s >> a[i].e >> a[i].d;
    
        ll l=0,r=1e9;
    
        while(l<r){
            ll mid=l+r>>1;
            if(get(mid)&1)
                r=mid;
            else
                l=mid+1;
        }
        ll ans=get(r)-get(r-1);
        if(ans&1)
            cout<<l<<' '<<ans<<endl;
        else
            puts("There's no weakness.");    
    }
    int main(){
        int t;
        cin>>t;
        while(t--) 
            solve();
    }
    
  • 相关阅读:
    进度条加载
    插件
    倒计时
    阿里云oss教程
    拖拽排序插件 ---- Dragula
    预览图片代码
    Error: spawn xxxx ENOENT原因与解决
    关于环境配置的随笔
    js下载文件
    QuickStart系列:docker部署之redis
  • 原文地址:https://www.cnblogs.com/hhyx/p/12963503.html
Copyright © 2011-2022 走看看