Power Strings POJ - 2406 后缀数组

Given two strings a and b we define a*b to be their concatenation. For example, if a = "abc" and b = "def" then a*b = "abcdef". If we think of concatenation as multiplication, exponentiation by a non-negative integer is defined in the normal way: a^0 = "" (the empty string) and a^(n+1) = a*(a^n).

Input

Each test case is a line of input representing s, a string of printable characters. The length of s will be at least 1 and will not exceed 1 million characters. A line containing a period follows the last test case.

Output

For each s you should print the largest n such that s = a^n for some string a.

Sample Input

abcd
aaaa
ababab
.

Sample Output

1
4
3

Hint

This problem has huge input, use scanf instead of cin to avoid time limit exceed.
 
 
 
题意:
输入一个字符串,让你找出来这个串的最小循环节
 
 
题解:
对于答案就用for循环从1到n枚举(为什么不能用二分?因为这个判断没有单调性。即i不是循环节的话,你不能说i-1或者i+1也肯定不是循环节)
 
下一步就是判断枚举的这个i是不是循环节,怎么判断?
满足这三个条件:n%i==0 && Rank[0]-Rank[i]==1 && height[Rank[0]]==n-i
 
1、n%i==0这就肯定不需要说了
2、你要注意Rank[0]表示的是啥,他代表后缀[0...n]的排名是多少,如果循环节是i,那么Rank[0]-Rank[i]==Rank[i]-Rank[2*i]......==1
3、如果循环节是i,那么height[Rank[0]]==n-i,   height[Rank[0]]代表后缀[0..n]与后缀[i...n]的最长公共前缀,既然循环节是i,那么height[Rank[0]]的值也就等于n-i
 
还要注意这道题用后缀数组来做的话要用dc3模板,如果用Da模板会TLE
 
dc3模板AC代码:
 1 #include <cstdlib>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <algorithm>
 5 using namespace std;
 6 const int maxn = 3000010;
 7 #define F(x) ((x) / 3 + ((x) % 3 == 1 ? 0 : tb))
 8 #define G(x) ((x) < tb ? (x) * 3 + 1 : ((x) - tb) * 3 + 2)
 9 int wa[maxn], wb[maxn], Ws[maxn], wv[maxn], sa[maxn];
10 int Rank[maxn], height[maxn],r[maxn];
11 char s[maxn];
12 int c0(int *r, int a, int b)
13 {
14     return r[a] == r[b] && r[a + 1] == r[b + 1] && r[a + 2] == r[b + 2];
15 }
16 int c12(int k, int *r, int a, int b)
17 {
18     if (k == 2)
19         return r[a] < r[b] || r[a] == r[b] && c12(1, r, a + 1, b + 1);
20     return r[a] < r[b] || r[a] == r[b] && wv[a + 1] < wv[b + 1];
21 }
22 void Rsort(int *r, int *a, int *b, int n, int m)
23 {
24     for (int i = 0; i < n; i++) wv[i] = r[a[i]];
25     for (int i = 0; i < m; i++) Ws[i] = 0;
26     for (int i = 0; i < n; i++) Ws[wv[i]]++;
27     for (int i = 1; i < m; i++) Ws[i] += Ws[i - 1];
28     for (int i = n - 1; i >= 0; i--) b[--Ws[wv[i]]] = a[i];
29 }
30 void dc3(int  *r,int *sa,int n, int m)
31 {
32     int i, j, *rn = r + n, *san = sa + n, ta = 0, tb = (n + 1) / 3, tbc = 0, p;
33     r[n] = r[n + 1] = 0;
34     for (i = 0; i < n; i++) if (i % 3 != 0) wa[tbc++] = i;
35     Rsort(r + 2, wa, wb, tbc, m);
36     Rsort(r + 1, wb, wa, tbc, m);
37     Rsort(r, wa, wb, tbc, m);
38     for (p = 1, rn[F(wb[0])] = 0, i = 1; i < tbc; i++)
39         rn[F(wb[i])] = c0(r, wb[i - 1], wb[i]) ? p - 1 : p++;
40     if (p < tbc) dc3(rn, san, tbc, p);
41     else for (i = 0; i < tbc; i++) san[rn[i]] = i;
42     for (i = 0; i < tbc; i++) if (san[i] < tb) wb[ta++] = san[i] * 3;
43     if (n % 3 == 1) wb[ta++] = n - 1;
44     Rsort(r, wb, wa, ta, m);
45     for (i = 0; i < tbc; i++) wv[wb[i] = G(san[i])] = i;
46     for (i = 0, j = 0, p = 0; i < ta && j < tbc; p++)
47         sa[p] = c12(wb[j] % 3, r, wa[i], wb[j]) ? wa[i++] : wb[j++];
48     for (; i < ta; p++) sa[p] = wa[i++];
49     for (; j < tbc; p++) sa[p] = wb[j++];
50 }
51 void get_height(int n)
52 {
53     int i, j, k = 0;
54     for (i = 1; i <= n; i++) Rank[sa[i]] = i;
55     for (i = 0; i < n; height[Rank[i++]] = k)
56         for (k ? k-- : 0, j = sa[Rank[i] - 1]; r[i + k] == r[j + k]; k++);
57 }
58 int main()
59 {
60     while(~scanf("%s",s))
61     {
62         int n=strlen(s);
63         if(n==1 && s[0]=='.') break;
64         for(int i=0;i<n;++i)
65             r[i]=s[i];
66         r[n]='0';
67         dc3(r,sa,n+1,200);
68         get_height(n);
69         int  flag=0;
70         for(int i=1;i<n;++i)  //枚举循环节长度
71         {
72             if(n%i==0 && Rank[0]-Rank[i]==1 && height[Rank[0]]==n-i)
73             {
74                 flag=1;
75                 printf("%d\n",n/i);
76                 break;
77             }
78         }
79         if(!flag)
80             printf("1\n");
81     }
82     return 0;
83 }

 

Da模板TLE代码:

 1 #include <cstdlib>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 const int N = 1000010;
 8 int x[N], y[N], c[N];
 9 int rank[N], height[N];
10 int sa[N],n,k;
11 char s[N];
12 bool pan(int *x,int i,int j,int k,int n)
13 {
14     int ti=i+k<n?x[i+k]:-1;
15     int tj=j+k<n?x[j+k]:-1;
16     return x[i]==x[j]&&ti==tj;
17 }
18 void build_SA(int n,int r)
19 {
20     int *x=rank,*y=height;
21     for(int i=0; i<r; i++)c[i]=0;
22     for(int i=0; i<n; i++)c[s[i]]++;
23     for(int i=1; i<r; i++)c[i]+=c[i-1];
24     for(int i=n-1; i>=0; i--)sa[--c[s[i]]]=i;
25     r=1;
26     x[sa[0]]=0;
27     for(int i=1; i<n; i++)
28         x[sa[i]]=s[sa[i]]==s[sa[i-1]]?r-1:r++;
29     for(int k=1; r<n; k<<=1)
30     {
31         int yn=0;
32         for(int i=n-k; i<n; i++)y[yn++]=i;
33         for(int i=0; i<n; i++)
34             if(sa[i]>=k)y[yn++]=sa[i]-k;
35         for(int i=0; i<r; i++)c[i]=0;
36         for(int i=0; i<n; i++)++c[x[y[i]]];
37         for(int i=1; i<r; i++)c[i]+=c[i-1];
38         for(int i=n-1; i>=0; i--)sa[--c[x[y[i]]]]=y[i];
39         swap(x,y);
40         r=1;
41         x[sa[0]]=0;
42         for(int i=1; i<n; i++)
43             x[sa[i]]=pan(y,sa[i],sa[i-1],k,n)?r-1:r++;
44     }
45     for(int i=0; i<n; i++)rank[i]=x[i];
46 }
47 void get_height(int n)
48 {
49     int i,j,k=0;
50     for(i=1; i<=n; i++)rank[sa[i]]=i;
51     for(i=0; i<n; i++)
52     {
53         if(k)k--;
54         else k=0;
55         j=sa[rank[i]-1];
56         while(s[i+k]==s[j+k])k++;
57         height[rank[i]]=k;
58     }
59 }
60 int check(int len)
61 {
62     int i=2,cnt=0;
63     while(1)
64     {
65         while(i<=n && height[i]>=len)
66             cnt++,i++;
67         if(cnt+1>=k)return 1;
68         if(i>=n)return 0;
69         while(i <=n &&height[i]<len)
70             i++;
71         cnt=0;
72     }
73 }
74 
75 int main()
76 {
77     while(~scanf("%s",s))
78     {
79         n=strlen(s);
80         if(n==1 && s[0]=='.') break;
81         s[n]='0';
82         build_SA(n+1,200);
83         get_height(n);
84         //printf("%d %d %d\n",rank[0],rank[3],height[rank[0]]);
85         int  flag=0;
86         for(int i=1;i<n;++i)  //枚举循环节长度
87         {
88             if(n%i==0 && rank[0]-rank[i]==1 && height[rank[0]]==n-i)
89             {
90                 flag=1;
91                 printf("%d\n",n/i);
92                 break;
93             }
94         }
95         if(!flag)
96             printf("1\n");
97     }
98     return 0;
99 }

 

posted @ 2020-02-18 15:55  kongbursi  阅读(116)  评论(0编辑  收藏  举报