Power Strings
Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 25921 | Accepted: 10857 |
Description
Input
Output
Sample Input
abcd aaaa ababab .
Sample Output
1 4 3
Hint
Source
先说说后缀数组,比如ababab
我们枚举重复串的长度len
比如len=2
如果说此时满足要求,那么后缀 0 和 后缀 2 的公共部分必定有 n - len 的长度
后缀 0 :ababab
后缀 2 :abab
所以穷举 len 即可
复杂度O(N),然后后缀数组O(NlogN) + O(N)
一交poj,超时了。。。。。
后来看了网上题解才发现后缀数组确实要超时。。。都是用kmp写的
(以下转自别人博客)
对于数组s[0~n-1],计算next[0~n](多计算一位)。
考虑next[n],假设t=n-next[n],如果n%t==0,则t就是问题的解,否则解为1。
这样考虑:
比如字符串"abababab",
a b a b a b a b *
next -1 0 1 2 3 4 5 6 7
考虑这样的模式匹配,将"abababab#"当做主串,"abababab*"当做模式串,于是进行匹配到n(n=8)时,出现了不匹配:
主串 abababab#
模式串 abababab*
于是模式串需要回溯到next[*]=7,这之前的主串和模式串对应相等,于是需要模式串向右滚动的位移是d=n-next[n]=2,即:
123456789
主串 abababab#
模式串 abababab*
于是可以看出,s[0~1]=s[3~4]=s[5~6]=s[7~8]。
所以位移d=n-next[n]可以看作是构成字符串s的字串(如果n%d==0,存在这样的构成),相应的重复次数也就是n/d。
这样O(N)就可以了
测评情况(POJ)(超时的是后缀数组)
C++ AC Code(kmp)
/*http://blog.csdn.net/jiangzh7
By Jiangzh*/
#include<cstdio>
#include<cstring>
char s[1000000+10];
int len;
int next[1000000+10];
void getnext()
{
memset(next,0,sizeof(next));
next[0]=-1;
int j=0,k=-1;
while(j<len)
{
if(k==-1||s[j]==s[k]) next[++j]=++k;
else k=next[k];
}
}
int main()
{
freopen("poj2406.in","r",stdin);
freopen("2406kmp.out","w",stdout);
while(1)
{
memset(s,0,sizeof(s));
scanf("%s",s);len=strlen(s);
if(!strcmp(s,".")) break;
getnext();
//for(int i=0;i<=len;i++) printf("%d ",next[i]);puts("");
if(len!=next[len] && len%(len-next[len])==0) printf("%d\n",len/(len-next[len]));
else printf("1\n");
}
return 0;
}
C++ TLE Code(Suffix Array)
/*http://blog.csdn.net/jiangzh7
By Jiangzh*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1000000+10;
char s[N];
int rank[N],sa[N];
int c[N],tmp[N];
int height[N];
int lcp[N];
bool cmp(int *r,int a,int b,int l)
{ return r[a]==r[b] && r[a+l]==r[b+l]; }
void DA(int n,int m)
{
int i,j,p,*x=rank,*y=tmp;
memset(c,0,sizeof(c));
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,p=1;p<n;j*=2,m=p)
{
for(p=0,i=n-j;i<n;i++) y[p++]=i;
for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
memset(c,0,sizeof(c));
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); x[sa[0]]=0;
for(p=1,i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++;
}
for(i=0;i<n;i++) rank[sa[i]]=i;
int k=0;
for(i=0;i<n;height[x[i++]]=k)
for(k?k--:0,j=sa[x[i]-1];s[i+k]==s[j+k];k++);
}
void work()
{
int n=strlen(s);s[n++]='$';
DA(n,'z'+1);
/*for(int i=0;i<n;i++)
{
printf("%d %d ",sa[i],height[i]);
puts(s+sa[i]);
}*/
lcp[rank[0]]=0x3f3f3f3f;
for(int i=rank[0]-1;i>0;i--) lcp[i]=min(lcp[i+1],height[i+1]);
for(int i=rank[0]+1;i<n;i++) lcp[i]=min(lcp[i-1],height[i]);
//for(int i=0;i<n;i++) printf("%d ",lcp[i]);puts("");
for(int len=1;len<n;len++)
if((n-1)%len==0)
{
if(lcp[rank[len]]==(n-1)-len)
{
printf("%d\n",(n-1)/len);
break;
}
}
}
int main()
{
freopen("poj2406.in","r",stdin);
freopen("poj2406.out","w",stdout);
while(1)
{
memset(sa,0,sizeof(sa));
memset(rank,0,sizeof(rank));
memset(c,0,sizeof(c));
memset(tmp,0,sizeof(tmp));
memset(s,0,sizeof(s));
scanf("%s",s);
if(!strcmp(s,".")) break;
work();
}
return 0;
}