Educational Codeforces Round 105 (Rated for Div. 2) C

C. 1D Sokoban

我们左右两边其实是一样的 我们就针对右边讨论 左边转化成整数就是右边一样的了
对于我们第一个箱子 我们枚举第一个箱子到每一个特殊点 这样显然包含最优解
考虑反例 要是我们这个箱子不放在一个特殊点 而是放在一个特殊点前面一些位置
我们显然应该把就近的特殊点全部覆盖掉 所以我们越往后移动 也就是舍去了前面一些不特殊的点
后面要是有特殊点 我们就赚了 要是没特殊点 我们也不会减少贡献 要是有特殊点上面有箱子
我们的贡献也是不减的 所以结论成立
我们枚举每一个特殊点 来做这堆箱子的起始点 然后整出长度 再搞出他没有受到影响的后缀有多少箱子
最后让这个后缀加上我们该范围内的特殊点数目就可以更新答案了
代码比较长但是思路比较简单
记得函数传参不能传较长的vector不然是n2的!!!

void solve(){
    int n,m;cin>>n>>m;
    vector<int>l,r,z,y,L,R,Z,Y;
    map<int,int>mp;
    for(int i=1;i<=n;i++){
        int x;cin>>x;
        if(x<0)l.push_back(-x);
        else r.push_back(x);
    }
    sort(all(l));
    for(int i=0;i<l.size();i++)z.push_back(l[i]-i);
    for(int i=0;i<r.size();i++)y.push_back(r[i]-i);
    for(int i=1;i<=m;i++){
        int x;cin>>x;
        mp[x]=1;
        if(x<0) L.push_back(-x);
        else R.push_back(x);
    }
    sort(all(L));
    for(auto i:r){
        if(mp.count(i))Y.push_back(1);
        else Y.push_back(0);
    }
    for(auto i:l){
        if(mp.count(-i))Z.push_back(1);
        else Z.push_back(0);
    }
    for(int i=(int)Z.size()-2;i>=0;i--)
        Z[i]+=Z[i+1];
    for(int i=(int)Y.size()-2;i>=0;i--)
        Y[i]+=Y[i+1];
    int ans_l=0,ans_r=0;
    for(int i=0;i<R.size();i++){
        int f=R[i];
        auto it=upper_bound(all(y),f);
        prev(it);
        int len=it-y.begin();
        int e=R[i]+len-1;
        int t=(upper_bound(all(R),e)-R.begin())-
                (lower_bound(all(R),f)-R.begin());
        if(len>=(int)Y.size())ans_r=max(ans_r,t);
        else ans_r=max(ans_r,t+Y[len]);
    }
    for(int i=0;i<L.size();i++){
        int f=L[i];
        auto it=upper_bound(all(z),f);
        prev(it);
        int len=it-z.begin();
        int e=L[i]+len-1;
        int t=(upper_bound(all(L),e)-L.begin())-
              (lower_bound(all(L),f)-L.begin());
        if(len>=(int)Z.size())ans_l=max(ans_l,t);
        else ans_l=max(ans_l,t+Z[len]);
    }
    cout<<ans_l+ans_r<<endl;
}
posted @ 2022-11-09 15:05  ycllz  阅读(19)  评论(0)    收藏  举报