[BZOJ2803][Poi2012]Prefixuffix
2803: [Poi2012]Prefixuffix
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 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
ababbabababbaab
Sample Output
6
HINT
Source
这题好厉害啊!!!
设$f[i]=[i+1,n-i]$这个子串中前缀和后缀最长的一样的。
这样答案就=$\max{f[i]+i},其中[1,i]=[n-i+1,n]$
发现一个性质$f[i-1]<=f[i]+2$,这样就可以类似一个单调栈来$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 }
就让我永远不在这里写什么有意义的话--月下孤狼