Wannafly挑戰賽19-F-K串(hash+莫隊)
阿新 • • 發佈:2018-12-24
題目描述
ZZT 得到了一個字串 S 以及一個整數 K。
WZH 在 1995 年提出了“優雅 K 串”的定義:這個字串每一種字元的個數都是 K 的倍數。
現在 ZZT 想要對字串進行 Q 次詢問,第 i 次詢問給出一個區間 [Li, Ri],他想計算 [Li, Ri] 中有多少個子串是“優雅 K 串”。
由於 ZZT 忙於工作,所以他把這個問題交給了你,請你幫忙解決。
輸入描述:
第一行輸入一個正整數 K。 第二行輸入一個字串 S。 第三行輸入一個正整數 Q,表示有 Q 次詢問。
接下來 Q 行,每行輸入兩個正整數 Li 和 Ri,表示第 i 次詢問。
1 ≤ K ≤ 50.
1≤ | S | ≤ 3 x 104 且 S 僅包含小寫英文字母.
1≤ Q ≤ 3 x 104.
1 ≤ Xi ≤ Yi ≤ N.
輸出描述:
每次詢問,輸出一個正整數,表示滿足條件的“優雅 K 串”的數量。
示例1
輸入
1 abc 3 1 3 1 2 2 3
輸出
6 3 3
#include<math.h> #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define maxn 100005 #define mod 1000000009 #define ll long long char s[maxn]; int k,q,pos[maxn],sum[maxn]; int cnt,l,r,num,sm[maxn]; ll tmp,ans[maxn],c[maxn],v[maxn]; struct node { int l,r,id; }a[maxn]; bool comp(node a,node b) { if(pos[a.l]!=pos[b.l]) return pos[a.l]<pos[b.l]; return a.r<b.r; } int main(void) { scanf("%d",&k); scanf("%s",s+1); scanf("%d",&q); for(int i=1;i<=q;i++) scanf("%d%d",&a[i].l,&a[i].r),a[i].id=i; int len=strlen(s+1); int relen=(int)sqrt(len+0.5); for(int i=1;i<=q;i++) pos[i]=(i-1)/relen+1; sort(a+1,a+q+1,comp); v[++cnt]=0; for(int i=1;i<=q;i++) { sum[s[i]-'a']=(sum[s[i]-'a']+1)%k; for(int j=0;j<26;j++) c[i]=(c[i]*131+sum[j])%mod; v[++cnt]=c[i]; } sort(v+1,v+cnt+1); num=unique(v+1,v+cnt+1)-v-1; for(int i=0;i<=q;i++) c[i]=lower_bound(v+1,v+cnt+1,c[i])-v; sm[1]=1; for(int i=1;i<=q;i++) { while(r<a[i].r) r++,tmp+=sm[c[r]],sm[c[r]]++; while(r>a[i].r) sm[c[r]]--,tmp-=sm[c[r]],r--; while(l+1<a[i].l)//因為字首和左開右閉 sm[c[l]]--,tmp-=sm[c[l]],l++; while(l+1>a[i].l) l--,tmp+=sm[c[l]],sm[c[l]]++; ans[a[i].id]=tmp; } for(int i=1;i<=q;i++) printf("%d\n",ans[i]); return 0; }