Codeforces Round #543 (Div. 2) D 双指针 + 模拟

https://codeforces.com/contest/1121/problem/D

题意

给你一个m(<=5e5)个数的序列,选择删除某些数,使得剩下的数按每组k个数以此分成n组(n*k<=m),存在只要一组满足和目标集合s(|s|<=k)匹配(即集合中存在的数,组内一定存在)

题解

  • 重点:找出至少一组满足要求的数
  • 假设[l,r]内满足要求,还需要满足:\((l-1)/k*k+(m-r)/k*k>=k*(n-1)\),可以用双指针,对于每个l可以处理出最小的r满足要求
  • 这样就把数组分成了三段[1,l-1],[l,r],[r+1,m],第一段[1,l-1]删除数字使得可以被k整除(没有限制随便删除),第二段[l,r]分成两种情况:
    1. (r-l+1)>k:去掉(r-l+1-k)个不符合要求的数
    2. (r-l+1)==k:不用删除任何数

坑点

  • 对于第二段的第一种情况,不符合要求的数包括:
    1. 不在集合内的数
    2. 在集合内,但超出集合数量的数
    • 模拟时应该优先删除不在集合内的数,并统计数目,数目不够再删除在集合内的数,假如优先删除在集合内的数,有可能会导致[l,r]内不符合要求

代码

#include<bits/stdc++.h>
#define M 500005
using namespace std;
int m,k,n,s,a[M],mp[M],x,kd,cnt,vi[M],l,r,ed,i,rm,CNT;
map<int,int>mk;
vector<int>ans;
int main(){
    cin>>m>>k>>n>>s;
    for(i=1;i<=m;i++)scanf("%d",&a[i]);
    for(i=1;i<=s;i++){
        scanf("%d",&x);
        if(!mp[x]){kd++;}
        mp[x]++;
    }
    cnt=0;
    for(l=1;l<=m;){
        while(cnt<kd&&r<=m){
            vi[a[++r]]++;
            if(vi[a[r]]==mp[a[r]])cnt++;
            //if(vi[r]==mp[x]+1)cnt--;
        }
        if(r>m)break;
        if(cnt==kd){
            ed=max(l+k-1,r);
            if(ed<=m){
                if((l-1)/k+(m-ed)/k>=n-1){
                    rm=(l-1)%k;
                    for(i=1;i<=rm;i++)ans.push_back(i);
                    mk.clear();
                    if(r>l+k-1){
                        CNT=r-(l+k-1);
                    for(i=l;i<=ed;i++){
                        if(mp[a[i]]&&mk[a[i]]<mp[a[i]]){
                            mk[a[i]]++;
                        }else if(CNT){
                            ans.push_back(i);
                            CNT--;
                        }
                    }
                    }                   
                    printf("%d\n",ans.size());
                    for(i=0;i<ans.size();i++)
                        printf("%d ",ans[i]);   
                    return 0;
                }
            }
        }
        if(vi[a[l]]==mp[a[l]])cnt--;
        vi[a[l++]]--;
    }
    cout<<-1;
}

猜你喜欢

转载自www.cnblogs.com/VIrtu0s0/p/10486509.html
今日推荐