浙大集训Day-10:A.Sequence
我们定义一个序列\(a\),值域\([1,k]\)是好的,当且仅当对于\(1\)到\(k\)的每一个数\(j\),在序列里的出现次数都在\([l_j,r_j]\)之间。
询问有多少个这样的子串,是好的。
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+100;
int n,k,a[maxn];
int l[maxn],r[maxn];
int cnt[maxn];
int cc=0;
int p1[maxn],p2[maxn];
int main () {
scanf("%d%d",&n,&k);
for (int i=1;i<=n;i++) scanf("%d",a+i);
for (int i=1;i<=k;i++) scanf("%d%d",l+i,r+i);
int L=1,R=1;
//先求每个点左边第一个满足的点
cnt[a[1]]=1;
for (int i=1;i<=k;i++) if (cnt[i]>=l[i]) cc++;
while (1) {
while (R<n) {
if (cc==k&&R>=L) {
//如果已经全部满足,就不用了
break;
}
else {
R++;
cnt[a[R]]++;
if (cnt[a[R]]==l[a[R]]) cc++;
}
}
if (cc==k) p1[L]=R;
cnt[a[L]]--;
if (cnt[a[L]]==l[a[L]]-1) cc--;//如果第一次突破下界,cc--
L++;
if (L>n) break;
}
L=1,R=1;
for (int i=1;i<=k;i++) cnt[i]=0;
cnt[a[1]]=1;
cc=0;
for (int i=1;i<=k;i++) if (cnt[i]>r[i]) cc++;
while (1) {
while (R<n) {
if (cnt[a[R+1]]+1<=r[a[R+1]]) {
R++;
cnt[a[R]]++;
}
else {
break;
}
}
if (cc==0) p2[L]=R;
cnt[a[L]]--;
if (cnt[a[L]]==r[a[L]]) cc--;//如果第一次回到上界,cc--
L++;
if (L>n) break;
}
long long ans=0;
for (int i=1;i<=n;i++) {
if (p1[i]>p2[i]) continue;
if (!p1[i]||!p2[i]) continue;
//printf("%d %d %d\n",i,p1[i],p2[i]);
ans+=p2[i]-p1[i]+1;
}
printf("%lld\n",ans);
}