Acesrc is a famous string theorist at Nanjing University second to none. He insists that we should always say an important thing k times. He also believes that every string that can be obtained by concatenating k
copies of some nonempty string is splendid. So, he always teaches newcomers, ``String theory problems are important! String theory problems are important! ... String theory problems are important!"
Today, he wants to examine whether the newcomers remember his instruction. He presents a string consisting of lower case letters and asks them the number of splendid substrings of the presented string. No one can solve this problem, and they will be scolded for hours. Can you help them solve this problem?
Note that equal splendid substrings occurred in different positions should be counted separately.Input
The first line of input consists of a single integer T
(1≤T≤10)
, denoting the number of test cases. Each test case starts with a single line of an integer k (1≤k≤20). The second line of a test case is a string S consisting of lower case letters only, the length of which is between 1 and 3×105 inclusive. The sum of the lengths of strings in all test cases never exceeds 106
.
Output
For each test case, print the answer as a single integer in a single line.
Sample Input
3 2 aabb 2 abababab 3 abcSample Output
2 6 0
题目大意:询问多少个子串是可以通过k次循环得到的。
解题思路:考虑直接枚举长度为k的倍数的所有子串,显然时间复杂度过高。
注意到所有子串都满足存在一个最小循环节,k=1的情况除外,这时特判即可。
考虑对每个串直接求最小循环节,显然也会超时。
转换思路:为循环节的串,那么考虑枚举x,然后设立i,i+x⋯
- 求出所有以x
- 这些关键点。
- 依次考虑相邻的两个关键点,通过后缀数组求出lcp,lcs
- ,得到覆盖当前关键点的串。
- 那么串对答案的贡献为len−kx+1
/* @Author: Top_Spirit @Language: C++ */ #include <bits/stdc++.h> using namespace std ; typedef unsigned long long ull ; typedef long long ll ; const int Maxn = 3e5 + 10 ; const int INF = 0x3f3f3f3f ; const double PI = acos(-1.0) ; const int seed = 133 ; struct Node { int sa[Maxn] ; int t1[Maxn], t2[Maxn], c[Maxn] ; int Rank[Maxn], height[Maxn] ; int dp[Maxn][20], lok[Maxn] ; void build_sa(char s[], int n, int m){ int i, j, p, *x = t1, *y = t2 ; for(i = 0; i < m; i++) c[i] = 0 ; for(i = 0; i < n; i++) c[x[i] = s[i]]++ ; for(i = 1; i < m; i++) c[i] += c[i-1] ; for(i = n - 1; i >= 0; i--) sa[--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(sa[i] >= j) y[p++] = sa[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 >= 0; i--) sa[--c[x[y[i]]]] = y[i] ; swap(x,y) ; p=1; x[sa[0]] = 0; for(i = 1; i < n; i++) x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + j] == y[sa[i] + j] ? p-1 : p++ ; if(p >= n) break ; m = p ; } } void getHeight(char s[],int n){ int i, j, k = 0 ; for(i = 0; i <= n; i++) Rank[sa[i]] = i ; for(i = 0; i < n; i++){ if(k) k-- ; j = sa[Rank[i] - 1] ; while(s[i + k] == s[j + k]) k++ ; height[Rank[i]] = k ; } } void initRmq(int n, int b[]){ lok[0] = -1 ; for (int i = 1; i <= n; i++){ lok[i] = ((i & (i - 1)) == 0) ? lok[i - 1] + 1 : lok[i - 1] ; dp[i][0] = b[i] ; } for (int j = 1; j <= lok[n]; j++){ for(int i = 1; i + (1 << j) - 1 <= n; i++){ dp[i][j] = min(dp[i][j - 1], dp[i + (1 << (j - 1))][ j - 1]) ; } } } int getRmq(int l, int r){ int k = lok[r - l + 1] ; return min(dp[l][k], dp[r - (1 << k) + 1][k]) ; } int lcp (int l, int r){ int L = Rank[l] ; int R = Rank[r] ; // cout << L << " " << R << endl ; if (L > R) swap(L, R) ; return getRmq(L + 1, R) ; } }L, R; char t[Maxn]; char s[Maxn] ; int main(){ int T, k ; scanf("%d", &T) ; while(T--){ scanf("%d", &k) ; ll ans = 0 ; scanf("%s",s) ; int len = strlen(s); for(int i = 0; i < len; i++) t[i] = s[len - i - 1] ; t[len] = '\0' ; if (k == 1) { ans = 1ll * (1 + len) * len / 2 ; printf("%lld\n", ans) ; continue ; } L.build_sa(s, len + 1, 520) ; L.getHeight(s, len) ; L.initRmq(len, L.height) ; R.build_sa(t, len + 1, 520) ; R.getHeight(t, len) ; R.initRmq(len, R.height) ; int last ; for (int j = 1; j < len; j++){ last = 0 ; for (int i = last + j; i < len; i += j){ int r = i + L.lcp(last, i) - 1 ; if (r >= i + j || r >= len) continue ; int l = last - R.lcp(len - i - 1, len - last - 1) + 1 ; int num = r - l + 1 ; ans += max(0, num - k * j + 1) ; last = i ; } } printf("%lld\n", ans) ; } return 0; } /* */