地址:http://acm.split.hdu.edu.cn/showproblem.php?pid=6194
题目:
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 486 Accepted Submission(s): 125
Problem Description
Uncle Mao is a wonderful ACMER. One day he met an easy problem, but Uncle Mao was so lazy that he left the problem to you. I hope you can give him a solution.
Given a string s, we define a substring that happens exactly k times as an important string, and you need to find out how many substrings which are important strings.
Given a string s, we define a substring that happens exactly k times as an important string, and you need to find out how many substrings which are important strings.
Input
The first line contains an integer 6.
Output
For each test case, print the number of the important substrings in a line.
Sample Input
2
2
abcabc
3
abcabcabcabc
Sample Output
6
9
Source
思路:
sam会卡指针版的代码,不明白卡这么点内存有什么意思。
后缀自动机做法:建立sam后,统计出cnt数组,这一步要拓扑排序后倒着dp。
后缀数组做法:用f[i][j]表示height(i,j)的区间最小值,然后滑动大小为k的窗口,则贡献是max(0,f[i][j]-max(height[i-1],height[j+1]) )
后缀自动机做法:
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 char ss[100004]; 6 int ans; 7 8 struct SAM 9 { 10 static const int MAXN = 100001<<1;//大小为字符串长度两倍 11 static const int LetterSize = 26; 12 13 int tot, last, ch[MAXN][LetterSize], fa[MAXN], len[MAXN]; 14 int sum[MAXN], tp[MAXN], cnt[MAXN]; //sum,tp用于拓扑排序,tp为排序后的数组 15 16 void init( void) 17 { 18 last = tot = 1; 19 len[1] = 0; 20 memset(ch,0,sizeof ch); 21 memset(fa,0,sizeof fa); 22 memset(cnt,0,sizeof cnt); 23 } 24 25 void add( int x) 26 { 27 int p = last, np = last = ++tot; 28 len[np] = len[p] + 1, cnt[last] = 1; 29 while( p && !ch[p][x]) ch[p][x] = np, p = fa[p]; 30 if( p == 0) 31 fa[np] = 1; 32 else 33 { 34 int q = ch[p][x]; 35 if( len[q] == len[p] + 1) 36 fa[np] = q; 37 else 38 { 39 int nq = ++tot; 40 memcpy( ch[nq], ch[q], sizeof ch[q]); 41 len[nq] = len[p] + 1, fa[nq] = fa[q], fa[q] = fa[np] = nq; 42 while( p && ch[p][x] == q) ch[p][x] = nq, p = fa[p]; 43 } 44 } 45 } 46 47 void toposort( void) 48 { 49 for(int i = 1; i <= len[last]; i++) sum[i] = 0; 50 for(int i = 1; i <= tot; i++) sum[len[i]]++; 51 for(int i = 1; i <= len[last]; i++) sum[i] += sum[i-1]; 52 for(int i = 1; i <= tot; i++) tp[sum[len[i]]--] = i; 53 } 54 } sam; 55 56 57 int main(void) 58 { 59 //freopen("in.acm","r",stdin); 60 int t,k;cin>>t; 61 while(t--) 62 { 63 ans=0; 64 sam.init(); 65 scanf("%d%s",&k,ss); 66 for(int i=0,len=strlen(ss);i<len;i++) sam.add(ss[i]-'a'); 67 sam.toposort(); 68 for(int i=sam.tot;i;i--) 69 { 70 int p=sam.tp[i],fp=sam.fa[p]; 71 sam.cnt[fp]+=sam.cnt[p]; 72 if(sam.cnt[p]==k) 73 ans+=sam.len[p]-sam.len[fp]; 74 } 75 printf("%d\n",ans); 76 } 77 78 return 0; 79 }
后缀数组做法:
1 #include <cstdlib> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 #include <set> 6 #include <iostream> 7 const int N = 200005; 8 int sa[N],s[N],wa[N], wb[N], ws[N], wv[N]; 9 int rank[N], height[N]; 10 char ss[N]; 11 bool cmp(int r[], int a, int b, int l) 12 { 13 return r[a] == r[b] && r[a+l] == r[b+l]; 14 } 15 16 void da(int r[], int sa[], int n, int m) 17 { 18 int i, j, p, *x = wa, *y = wb; 19 for (i = 0; i < m; ++i) ws[i] = 0; 20 for (i = 0; i < n; ++i) ws[x[i]=r[i]]++; 21 for (i = 1; i < m; ++i) ws[i] += ws[i-1]; 22 for (i = n-1; i >= 0; --i) sa[--ws[x[i]]] = i; 23 for (j = 1, p = 1; p < n; j *= 2, m = p) 24 { 25 for (p = 0, i = n - j; i < n; ++i) y[p++] = i; 26 for (i = 0; i < n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j; 27 for (i = 0; i < n; ++i) wv[i] = x[y[i]]; 28 for (i = 0; i < m; ++i) ws[i] = 0; 29 for (i = 0; i < n; ++i) ws[wv[i]]++; 30 for (i = 1; i < m; ++i) ws[i] += ws[i-1]; 31 for (i = n-1; i >= 0; --i) sa[--ws[wv[i]]] = y[i]; 32 for (std::swap(x, y), p = 1, x[sa[0]] = 0, i = 1; i < n; ++i) 33 x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p-1 : p++; 34 } 35 } 36 37 void calheight(int r[], int sa[], int n) 38 { 39 int i, j, k = 0; 40 for (i = 1; i <= n; ++i) rank[sa[i]] = i; 41 for (i = 0; i < n; height[rank[i++]] = k) 42 for (k?k--:0, j = sa[rank[i]-1]; r[i+k] == r[j+k]; k++); 43 } 44 struct RMQ 45 { 46 int log2[N],mi[N][25]; 47 void init(int n) 48 { 49 for(int i = 0; i <= n; i ++)log2[i] = (i == 0 ? -1 : log2[i >> 1] + 1); 50 for(int j = 1; j < log2[n]; j ++) 51 for(int i = 1; i + (1 << j) <= n + 1; i ++) 52 mi[i][j] = std::min(mi[i][j - 1], mi[i + (1 << j - 1)][j - 1]); 53 } 54 int query(int ql, int qr) 55 { 56 int k = log2[qr - ql + 1]; 57 return std::min(mi[ql][k], mi[qr - (1 << k) + 1][k]); 58 } 59 } rmq; 60 int sc(int i,int k,int len) 61 { 62 if(k==1) return len-sa[i]; 63 return rmq.query(i+1,i+k-1); 64 } 65 int main() 66 { 67 int t,k;std::cin>>t; 68 while(t--) 69 { 70 int ans=0; 71 scanf("%d%s",&k,ss); 72 int len=strlen(ss); 73 for(int i=0;i<len;i++) 74 s[i]=ss[i]-'a'+1; 75 s[len]=0; 76 da(s,sa,len+1,28); 77 calheight(s,sa,len); 78 height[len+1]=0; 79 for(int i=1;i<=len;i++) 80 rmq.mi[i][0]=height[i]; 81 rmq.init(len); 82 for(int i=1;i<=len-k+1;i++) 83 ans+=std::max(sc(i,k,len)-std::max(height[i],height[i+k]),0); 84 printf("%d\n",ans); 85 } 86 return 0; 87 }