Hdu5785-Interesting(回文串处理)
Problem Description
Alice get a string S. She thinks palindrome string is interesting. Now she wanna know how many three tuple (i,j,k) satisfy 1≤i≤j<k≤length(S) , S[i..j] and S[j+1..k] are all palindrome strings. It's easy for her. She wants to know the sum of i*k of all required three tuples. She can't solve it. So can you help her? The answer may be very large, please output the answer mod 1000000007.
A palindrome string is a string that is same when the string is read from left to right as when the string is read from right to left.
A palindrome string is a string that is same when the string is read from left to right as when the string is read from right to left.
Input
The input contains multiple test cases.
Each test case contains one string. The length of string is between 1 and 1000000. String only contains lowercase letter.
Each test case contains one string. The length of string is between 1 and 1000000. String only contains lowercase letter.
Output
For each test case output the answer mod
1000000007.
Sample Input
aaa
abc
Sample Output
14
8
题意: 找三元组(i,j,k) 使得[i,j]和[j+1,k]都是回文串。计算所有i*k的和模上1000000007.
解析:先跑一边manacher.然后处理4个数组
C[0][i]: 代表对于下标i的点,他所在的回文串(回文串在他右边)中心下标*2的和
C[1][i]: 代表对于下标i的点,他所在的回文串(回文串在他左边)中心下标*2的和
C[2][i]: 代表对于下标i的点,他所在的回文串个数(回文串在他右边)
C[3][i]: :代表对于下标i的点,他所在的回文串个数(回文串在他左边)
对于以x为左端点的回文串,那么它右边的所有k的和为C[0][x]-C[2][x]*x(想一想为甚么,得到的恰好是所有包含x为左端点的回文的长度),以
x为右端点同理。还要注意奇偶性,我参照了别人的写法。
代码:
#include<cstdio> #include<cstring> #include<string> #include<algorithm> using namespace std; typedef long long LL; const int mod=1000000007; const int maxn=2000010; char org[maxn],S[maxn]; int p[maxn]; inline int manacher() //manacher实现部分 { S[0]='$'; S[1]='#'; int len=2; int L=strlen(org); for(int i=0;i<L;i++) { S[len++]=org[i]; S[len++]='#'; } S[len]='@'; S[len+1]=0; int ri=0,id; for(int i=1;i<len;i++) { if(ri>i) p[i]=min(p[2*id-i],ri-i); else p[i]=1; while(S[i+p[i]]==S[i-p[i]]) p[i]++; if(i+p[i]>ri) { ri=i+p[i]; id=i; } } return len-1; } int C[4][maxn]; void Modify(int k,int l,int r,int v) //修改 { if(l>r) return; C[k][l]=(C[k][l]+v)%mod; //l位置要加上v C[k][r+1]=(C[k][r+1]-v+mod)%mod; //r+1要减去v因为从l到r这一段是累加的,但是到r+1开始就要减掉了 } int main() { while(scanf("%s",org)!=EOF) { int len=manacher(); memset(C,0,sizeof(C)); for(int i=len;i>=1;i--) { Modify(0,i-p[i]+1,i,i); Modify(2,i-p[i]+1,i,1); } for(int i=1;i<=len;i++) { Modify(1,i,i+p[i]-1,i); Modify(3,i,i+p[i]-1,1); } for(int k=0;k<4;k++) for(int i=1;i<=len;i++) C[k][i]=(C[k][i]+C[k][i-1])%mod; int ans=0; for(int i=2;i<len-1;i+=2) { int a=i,b=i+2; int lsum=(C[0][b]-(LL)C[2][b]*(b/2)%mod+mod)%mod; int rsum=(C[1][a]-(LL)C[3][a]*(a/2)%mod+mod)%mod; ans=(ans+(LL)lsum*rsum%mod)%mod; } printf("%d\n",ans); } return 0; }