Link
记(m=|S|,p=lfloorfrac{n+m}2
floor),我们可以得到一个比较trivial的(O(m^2n))的dp算法。
设(f_{l,r,x})表示能够匹配(S_lcdots,S_r)的长度为(x)的回文串的个数。我们认为(l>r)时并不存在限制,但是(lle r+2)必须被满足。
先考虑边界情况:(f_{l,r,0}=[l>r],f_{l,r,1}=26[lge r])。
然后考虑如何转移,显然我们只需要考虑(xge2)的情况:
不难发现转移与(x)并没有关系,所以我们可以利用矩阵快速幂做到(O(m^6log n))。
我们可以把这个dp转化为路径计数问题:
起点为((1,m)),终点为((i,i))或((i,i-1))或((i,i-2)),步数为(p)。
对于((l,r)),若(l>r),则((l,r))向自身连(26)条自环。
否则若(S_l=S_r),则向自身连(25)条自环,向((l+1,r-1))连(1)条边。
否则向自身连(24)条自环,向((l+1,r),(l,r-1))连(1)条边。
假如我们固定了去掉自环后的路径,设该路径上有(a)个点有(26)个自环,(b)个点有(25)个自环,(c)个点有(24)个自环,那么可行的路径方案数就是([x^p]frac{x^{a+b+c-1}}{(1-26x)^a(1-25x)^b(1-24x)^c})。
那么我们可以先用(O(m^3))的dp求出对于所有的((a,b,c)),有多少种本质不同的去掉自环后的路径,再利用多项式快速幂+取模计算([x^p]frac{x^{a+b+c-1}}{(1-26x)^a(1-25x)^b(1-24x)^c})即可。时间复杂度为(O(m^3log n))。
考虑将分母多项式通分之后计算(x^p)的系数,那么我们可以把问题转化为常系数线性递推,然后利用矩阵快速幂计算,时间复杂度为(O(m^3log n))。
利用多项式快速幂+取模可以做到(O(m^3+log n))。
#include<cstdio>
#include<cstring>
const int N=405,P=10007;
int r,f[N][N][N],x[N][N];char str[N];
void inc(int&a,int b){a+=b-P,a+=a>>31&P;}
void dec(int&a,int b){a-=b,a+=a>>31&P;}
int add(int a,int b){return inc(a,b),a;}
int mul(int a,int b){return 1ll*a*b%P;}
struct matrix{int a[N][N];matrix(){memset(a,0,sizeof a);}int*operator[](int x){return a[x];}}E,I;
matrix mul(matrix a,matrix b)
{
matrix c;
for(int i=1;i<=r;++i) for(int j=i;j<=r;++j) for(int k=j;k<=r;++k) inc(c[i][k],mul(a[i][j],b[j][k]));
return c;
}
matrix pow(matrix a,int k)
{
matrix b;
for(int i=1;i<=r;++i) b[i][i]=1;
for(;k;k>>=1,a=mul(a,a)) if(k&1) b=mul(b,a);
return b;
}
int main()
{
int n,m,ans=0,cnt;
scanf("%s%d",str+1,&m),m+=n=strlen(str+1),cnt=(n+1)/2,r=n+cnt*2-1;
for(int i=1;i<=n;++i) f[i][i][0]=1,f[i][i+1][0]=i<n&&str[i]==str[i+1];
for(int i=n-1;i;--i)
for(int j=str[i]==str[i+1]? i+2:i+1;j<=n;++j)
if(str[i]==str[j]) for(int k=0;k<=n;++k) f[i][j][k]=f[i+1][j-1][k];
else for(int k=1;k<=n;++k) f[i][j][k]=add(f[i][j-1][k-1],f[i+1][j][k-1]);
for(int i=1;i<n;++i) E[i][i]=24,E[i][i+1]=1;
for(int i=n;i<n+cnt;++i) E[i][i]=25,E[i][i+cnt]=1,E[i-1][i]=1;
for(int i=n+cnt;i<=r;++i) E[i][i]=26;
I=pow(E,(m-1)/2),E=mul(E,I);
for(int i=0,p,k;i<n;++i)
{
p=(n-i-1)/2,k=E[n-i][n+cnt+p];
if(m&1&&~(n-i)&1) dec(k,I[n-i][n+p]);
inc(ans,mul(k,f[1][n][i]));
}
printf("%d",ans);
}