其他分享
首页 > 其他分享> > CF506E Mr. Kitayuta's Gift

CF506E Mr. Kitayuta's Gift

作者:互联网

Link
记\(m=|S|,p=\lfloor\frac{n+m}2\rfloor\),我们可以得到一个比较trivial的\(O(m^2n)\)的dp算法。
设\(f_{l,r,x}\)表示能够匹配\(S_l\cdots,S_r\)的长度为\(x\)的回文串的个数。我们认为\(l>r\)时并不存在限制,但是\(l\le r+2\)必须被满足。
先考虑边界情况:\(f_{l,r,0}=[l>r],f_{l,r,1}=26[l\ge r]\)。
然后考虑如何转移,显然我们只需要考虑\(x\ge2\)的情况:

\[f_{l,r,x}= \begin{cases} 26f_{l,r,x-1}&l>r\\ f_{l+1,r-1,x-2}+25f_{l,r,x-2}&l\le r\wedge S_l=S_r\\ f_{l+1,r,x-2}+f_{l,r-1,x-2}+24f_{l+1,r-1,x-2} \end{cases} \]

不难发现转移与\(x\)并没有关系,所以我们可以利用矩阵快速幂做到\(O(m^6\log 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^3\log n)\)。
考虑将分母多项式通分之后计算\(x^p\)的系数,那么我们可以把问题转化为常系数线性递推,然后利用矩阵快速幂计算,时间复杂度为\(O(m^3\log 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);
}

标签:return,matrix,Gift,int,路径,mul,CF506E,Kitayuta,log
来源: https://www.cnblogs.com/cjoierShiina-Mashiro/p/12627997.html