cf1121d 尺取

尺取,写起来有点麻烦

枚举左端点,然后找到右端点,,使得区间[l,r]里各种颜色花朵的数量满足b数组中各种花朵的数量,然后再judge区间[l,r]截取出后能否可以供剩下的n-1个人做花环

/*
给定序列A,分成n段,每段k个,
然后删掉A中的一些,但任要能组成n段,使得A中的一段包含序列B中的所有元素
如果可以输出删掉的元素,否则输出-1 
*/
#include<bits/stdc++.h>
using namespace std;
#define maxn 500005
int m,k,n,s,a[maxn],b[maxn],c[maxn];
int tot[maxn],cnt[maxn];//tot[i]表示第i种颜色需要的数量 
int l,r,sum,Max,all;
int judge(int l,int r){//判断除去l,r是否可行 
    int tmp1=l-1,tmp2=m-r;
    if(tmp1/k+tmp2/k+1>=n)return 1;
    return 0;
}
void add(int i){
    if(cnt[a[i]]==0)return;
    tot[a[i]]++;
    if(tot[a[i]]==cnt[a[i]])sum++;
}
void del(int i){
    if(cnt[a[i]]==0)return;
    tot[a[i]]--;
    if(tot[a[i]]==cnt[a[i]]-1)sum--;
}

int main(){
    cin>>m>>k>>n>>s;
    for(int i=1;i<=m;i++)cin>>a[i],Max=max(Max,a[i]);
    for(int i=1;i<=s;i++)cin>>b[i],Max=max(Max,b[i]);
    for(int i=1;i<=s;i++)cnt[b[i]]++;
    
    l=1,r=k;sum=0;
    for(int i=1;i<=Max;i++)
        if(cnt[i]!=0)all++;
    for(int i=l;i<=k;i++)
        add(i);
    
    while(1){
        if(sum==all){
            if(judge(l,r)){//可行 
                vector<int>v;
                v.clear();
                int tmp=r-l+1;
                for(int i=l;i<=r;i++){
                    if(cnt[a[i]]>0 || tmp==k)
                        cnt[a[i]]--;
                    else v.push_back(i),tmp--; 
                }        
                printf("%d
",v.size());
                for(int i=0;i<v.size();i++)
                    printf("%d ",v[i]);
                return 0;
            }
            del(l);l++;    
        }
        
        while(sum<all || l+k-1>r){
            r++;
            if(r>m)break;
            add(r);
        }
        if(r>m)break;
    }
    puts("-1");
} 
原文地址:https://www.cnblogs.com/zsben991126/p/10470567.html