• CF506E Mr. Kitayuta's Gift


    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)的情况:

    [f_{l,r,x}= egin{cases} 26f_{l,r,x-1}&l>r\ f_{l+1,r-1,x-2}+25f_{l,r,x-2}&lle rwedge 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^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);
    }
    
  • 相关阅读:
    HTML 特殊符号编码对照表
    C#删除字符串最后一个字符的几种方法
    c# 获取相对路径
    垂直滚动条代码
    Android微信分享功能实例+demo
    android之Itent.ACTION_PICK Intent.ACTION_GET_CONTENT妙用
    Android Camera 使用小结
    onSaveInstanceState和onRestoreInstanceState
    Android中的PopupWindow详解
    Unable to execute dex: java.nio.BufferOverflowException.解决办法
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12627997.html
Copyright © 2020-2023  润新知