[BZOJ2803][Poi2012]Prefixuffix

2803: [Poi2012]Prefixuffix

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 219  Solved: 95
[Submit][Status][Discuss]

Description


对于两个串S1、S2,如果能够将S1的一个后缀移动到开头后变成S2,就称S1和S2循环相同。例如串ababba和串abbaab是循环相同的。
给出一个长度为n的串S,求满足下面条件的最大的L:
1. L<=n/2
2. S的L前缀和S的L后缀是循环相同的。

 

Input

第一行一个正整数n (n<=1,000,000)。第二行n个小写英文字母,表示串S。

 

Output

一个整数,表示最大的L。

Sample Input

15
ababbabababbaab

Sample Output

6

HINT

 

Source

鸣谢Oimaster

[ Submit][ Status][ Discuss]


这题好厉害啊!!!

设$f[i]=[i+1,n-i]$这个子串中前缀和后缀最长的一样的。

这样答案就=$\max{f[i]+i},其中[1,i]=[n-i+1,n]$

发现一个性质$f[i-1]+2<=f[i]$,这样就可以类似一个单调栈来$O(n)$处理了。

(PS:POI卡hash,太差了!!)

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define N 1000010
 4 #define ll long long
 5 int pow[N][2],hash[N][2],mod[2]={99824435,1004535809},n,ans;
 6 char s[N];
 7 inline int gethash(int x,int l,int r)
 8 {return (hash[r][x]-(ll)hash[l-1][x]*pow[r-l+1][x]%mod[x]+mod[x])%mod[x];}
 9 inline bool check(int l,int r,int x)
10 {
11     return gethash(0,l,l+x-1)==gethash(0,r-x+1,r)&&gethash(1,l,l+x-1)==gethash(1,r-x+1,r);
12 }
13 int main()
14 {
15     scanf("%d\n",&n);
16     pow[0][0]=pow[0][1]=1;
17     for(int i=1;i<=n;i++)
18     {
19         s[i]=getchar();
20         for(int x=0;x<=1;x++)
21         hash[i][x]=((ll)hash[i-1][x]*233+s[i])%mod[x],
22         pow[i][x]=(ll)pow[i-1][x]*233%mod[x];
23     }
24     for(int i=n/2,j=0;i;i--,j=std::min(j+2,n/2-i))
25     if(check(1,n,i))
26     for(;~j;j--)
27     if(check(i+1,n-i,j))
28     {
29         ans=std::max(ans,i+j);
30         break;
31     }
32     printf("%d",ans);
33 }
View Code

 

你可能感兴趣的:([BZOJ2803][Poi2012]Prefixuffix)