浙大集訓Day-10:A.Sequence(雙指標)
阿新 • • 發佈:2021-11-13
浙大集訓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); }