• 2020ICPC江西C Charging(二分)


    首先观察到答案具有单调性

    其次,考虑如何check,一个朴素的想法就是枚举区间,之后判断覆盖这段区间的plan有几个,再取个min

    这样做复杂度较高,考虑一下优化。

    我们可以枚举右端点,之后把符合条件的左端点用树状数组维护,之后用一个指针去不断往前找到最远的符合覆盖大于二分值的点。

    注意,这个指针不要回溯,这样才能保证复杂度,因为这样遍历的次数才是n,否则复杂度随着数据变化,并且这个指针本来就不需要回溯,因为你之前不满足答案,右端点左移,显然更不可能满足答案

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pll;
    const int N=3e5+10;
    vector<int> num[N];
    int tr[N];
    int n,m;
    int lowbit(int x){
        return x&-x;
    }
    void add(int x,int c){
        int i;
        for(i=x;i<N;i+=lowbit(i)){
            tr[i]+=c;
        }
    }
    int sum(int x){
        int res=0;
        for(int i=x;i;i-=lowbit(i)){
            res+=tr[i];
        }
        return res;
    }
    bool check(int mid){
        int i;
        int now=n;
        memset(tr,0,sizeof tr);
        for(i=n;i>=1;i--){
            for(auto x:num[i]){
                add(x,1);
            }
            now=min(now,i);
            if(sum(now)<mid)
                continue;
            while(now>1&&sum(now-1)>=mid)
                now--;
            if(i-now+1>=mid)
                return true;
        }
        return false;
    }
    int main(){
        ios::sync_with_stdio(false);
        cin>>n>>m;
        int i;
        for(i=1;i<=m;i++){
            int x,y;
            cin>>x>>y;
            num[y].push_back(x);
        }
        int l=0,r=min(n,m)+1;
        while(l<r){
            int mid=l+r+1>>1;
            if(check(mid))
                l=mid;
            else
                r=mid-1;
        }
        cout<<l<<endl;
        return 0;
    }
    View Code
  • 相关阅读:
    DS博客作业04--图
    DS博客作业03--树
    DS博客作业02--栈和队列
    DS博客作业01--线性表
    C博客作业05--指针
    C语言博客作业04--数组
    C博客作业03--函数
    博客作业——循环结构
    C博客作业05-指针
    C博客作业04--数组
  • 原文地址:https://www.cnblogs.com/ctyakwf/p/14092957.html
Copyright © 2020-2023  润新知