CodeForces - 958 F2 Lightsabers (medium) . (尺取法)

传送门

题意:给你一个n和m,再给你一个长为n的序列和一个长为m的序列,问最少要删除多少元素,才能使第一个序列中的某个连续子串中恰好满足第二个序列对数字的要求

题解:尺取法,设l为左界,r为右界,若c[a[r]]==b[a[r]]则说明对b中第a[r]个数字的个数要求达到满足,则sum++。如果sum==m,则说明该子串满足条件,那么我们就要试图将左界前进(为了使删除要素更少,那么r-l+1肯定是最小的),此处注意要记得c[a[l]]减一,如果它在减之前的个数等于b[a[l]]则说明删减后,满足条件的个数减1,即sum-1

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <map>
#include <queue>
#include <vector>
#include <cstring>
#include <iomanip>
#include <set>
#include<ctime>
//CLOCKS_PER_SEC
#define se second
#define fi first
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define Pii pair<int,int>
#define Pli pair<ll,int>
#define ull unsigned long long
#define pb push_back
#define fio ios::sync_with_stdio(false);cin.tie(0)
const double Pi=3.14159265;
const double e=2.71828182;
const int N=3e5+5;
const ull base=163;
const int INF=0x3f3f3f3f;
using namespace std;
int a[N];
int b[N];int main(){
    int n,m;
    fio;
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    int sum=0;
    int pp=0;
    for(int i=1;i<=m;i++){
        cin>>b[i];
        if(b[i]==0)
        sum++;
        pp+=b[i];
    }
    int c[N];
    int l=1,r=1;
    int MIN=INF;
    int op=0;
    for(;;){
        while(r<=n&&sum<m){
            c[a[r]]++;
            if(c[a[r]]==b[a[r]])sum++;
            r++;
        }
        if(sum<m)break;
        MIN=min(MIN,r-l-pp);
        if(c[a[l]]==b[a[l]])sum--;
        c[a[l]]--;
        l++;
    }
    if(MIN!=INF)
    cout<<MIN<<endl;
    else cout<<-1<<endl;
    return 0;
}

 

posted @ 2018-04-14 23:59  采蘑菇的小西佬  阅读(177)  评论(0编辑  收藏  举报