标签:
题意: 找三元组(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; }
标签:
原文地址:http://www.cnblogs.com/wust-ouyangli/p/5745654.html