ACM-ICPC 2018 焦作賽區網路預賽 H String and Times (字尾陣列+容斥)
阿新 • • 發佈:2018-12-10
Now you have a string consists of uppercase letters, two integers A and B. We call a substring wonderful substring when the times it appears in that string is between A and B (A≤times≤B). Can you calculate the number of wonderful substrings in that string?
Input
Input has multiple test cases.
For each line, there is a string S, two integers A and B.
∑length(S)≤2×106,
1≤A≤B≤length(S)
Output
For each test case, print the number of the wonderful substrings in a line.
樣例輸入
AAA 2 3 ABAB 2 2
樣例輸出
2 3 字尾陣列求出現K次不同字串的板子題,只需稍作修改,在容斥的時候,減去大於B次的就可以。 程式碼實現:
/* Look at the star Look at the shine for U */ #include<bits/stdc++.h> #define ll long long #define PII pair<int,int> #define sl(x) scanf("%lld",&x) using namespace std; const int N = 200000+10; int temp1[N],temp2[N],sam[N],c[N],lcp[N],num[N],Rank[N],len; char s[N]; int dp[N][30]; void RMQ(int* arr, int n) { for(int i = 0;i < n;++i) dp[i][0] = arr[i]; for(int j = 1;(1<<j) <= n;++j) for(int i = 0;i+(1<<j)-1<n;++i) dp[i][j] = min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]); } ll ask(int l,int r) { int k = 0; while((1<<(k+1))<=r-l+1) ++k; ll ans = min(dp[l][k],dp[r-(1<<k)+1][k]); return ans; } bool judge(int* arr,int x,int y,int l) { if(arr[x] == arr[y] && arr[x+l] == arr[y+l]) return true; else return false; } ll query(int l,int r) { if (l == r) return len-sam[r]; return ask(l+1,r); } void init(int n,int m) { ++n; int i,j,p,*x = temp1,*y = temp2; for(i = 0;i < m;++i) c[i] = 0; for(i = 0;i < n;++i) c[x[i] = num[i]]++; for(i = 1;i < m;++i) c[i] += c[i-1]; for(i = n-1;i;--i) sam[--c[x[i]]] = i; for(j = 1;j <= n;j <<= 1) { p = 0; for(i = n-j; i<n;++i) y[p++] = i; for(i = 0;i < n;++i) if(sam[i] >= j) y[p++] = sam[i] - j; for(i = 0;i < m;++i) c[i] = 0; for(i = 0;i < n;++i) c[x[y[i]]]++; for(i = 1; i < m;++i) c[i] += c[i-1]; for(i = n-1;i;--i) sam[--c[x[y[i]]]] = y[i]; swap(x,y); p = 1; x[sam[0]] = 0; for (i = 1;i < n;++i) { if(judge(y,sam[i-1],sam[i],j)) x[sam[i]] = p-1; else x[sam[i]] = p++; } if(p >= n) break; m = p; } int k = 0; n--; for(i = 0;i <= n;++i) Rank[sam[i]] = i; for(i = 0;i < n;++i) { if(k)--k; j = sam[Rank[i]-1]; while(num[i+k] == num[j+k]) ++k; lcp[Rank[i]] = k; } } int main() { int t,k,x,i,j; while(~scanf("%s%d%d",s,&k,&x)) { len = strlen(s); for(i = 0;i <= len;i++) { Rank[i] = lcp[i] = sam[i] = 0; } for (i = 0; i < len; ++i) num[i] = s[i]-'A'+1; num[len] = 0; init(len,30); RMQ(lcp,len+1); ll ans = 0; for (i = 1;i+k-1 <= len;i++) { ans += query(i,i+k-1); //至少k個 if(i-1 > 0) ans -= query(i-1,i+k-1); if(i+x <= len) ans -= query(i,i+x); if(i-1 > 0 && i+x <= len) ans += query(i-1,i+x); } printf("%lld\n",ans); } return 0; }