• HDU 5863 cjj's string game (矩阵乘法优化递推)


    题目大意:用k种字符构建两个长度为n的字符串(每种字符有无限多个),要求对应位置字符相同的连续子串最长长度为m,问方法数。

    其中k,n,m是输入,n(1<=n<=1000000000), m(1<=m<=10), k(1<=k<=26).

    对题目解释更详细点儿,如下两串

    123456

    223466

    这个的“对应位置字符相同的连续子串最长长度”是3,是字符串“234”。

    解题思路,这题一看就是DP或者组合数学,但是不会组合数学,只能DP了
    dp[i][j]表示前i个字符,最后j个位置相同的方法数

    第三维01表示该状态是否包含了至少一个长度为m的“对应位置相同子串”

    dp[i][j][0]=dp[i-1][j-1][0]*k                                                          (0<j<m)
    dp[i][0][0]=sum(dp[i-1][0到m-1][0])*k*(k-1)
    dp[i][j][1]=dp[i-1][j-1][1]*k                                                          (0<j<=m)
    dp[i][0][1]=(sum(dp[i-1][0到m][1])+dp[i-1][m-1][0])*k*(k-1)
     
    由于第一维范围过大,且只和前一个状态有关,很明显想到矩阵乘法优化递推。完整代码如下:
     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 
     5 using namespace std;
     6 typedef long long ll;
     7 const int N = 30;
     8 const ll MOD=1000000007;
     9 struct Mat {
    10     ll mat[N][N];
    11     Mat()
    12     {
    13         memset(mat,0,sizeof(mat));
    14     }
    15     void clear(){
    16         memset(mat,0,sizeof(mat));
    17     }
    18 };
    19 
    20 ll num[N];
    21 int n, m,K;
    22 Mat a;
    23 
    24 void init() {
    25     //初始化状态转移矩阵
    26     a.clear();
    27     for(int j=0;j<m;j++)a.mat[0][j]=K*(K-1);
    28     for(int i=1;i<m;i++)a.mat[i][i-1]=K;
    29     for(int j=m;j<=2*m;j++)a.mat[m][j]=K*(K-1);
    30     for(int i=m+1;i<=2*m;i++)a.mat[i][i-1]=K;
    31     a.mat[2*m][m-1]=K;
    32 }
    33 
    34 Mat operator * (Mat a, Mat b) {
    35     Mat c;
    36     for(int i=0;i<=2*m;i++){
    37         for(int j=0;j<=2*m;j++){
    38             for(int k=0;k<=2*m;k++){
    39                 c.mat[i][j]+=b.mat[i][k]*a.mat[k][j];
    40                 c.mat[i][j]%=MOD;
    41             }
    42         }
    43     }
    44     return c;
    45 }
    46 
    47 Mat operator ^ (Mat a, int k) {
    48     //初状态
    49     Mat c;
    50     c.mat[0][0]=1;
    51     //快速幂
    52     for(; k; k >>= 1) {
    53         if(k&1) c = c*a;
    54         a = a*a;
    55     }
    56     return c;
    57 }
    58 
    59 int main() {
    60     //freopen("data.in", "r", stdin);
    61     int T;
    62     scanf("%d",&T);
    63     while(~scanf("%d%d%d",&n,&m,&K)) {
    64         //初始化状态转移矩阵
    65         init();
    66         //矩阵快速幂,初始左矩阵不是单位矩阵,是初状态
    67         a = a^n;
    68         //得到最终矩阵后求答案
    69         ll ans=0;
    70         for(int i = m; i <= 2*m; ++i) {
    71             ans+=a.mat[i][0];
    72             ans%=MOD;
    73         }
    74         printf("%lld
    ", ans);
    75     }
    76     return 0;
    77 }
    HDU 5863

    然后写这个主要是想记录下矩阵乘法的板子

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    
    using namespace std;
    typedef long long ll;
    const int N = 30;
    const long long MOD=1000000007;
    struct Mat {
        ll mat[N][N];
        Mat()
        {
            memset(mat,0,sizeof(mat));
        }
        void clear(){
            memset(mat,0,sizeof(mat));
        }
    };
    
    ll num[N];
    int n, m,K;
    Mat a;
    
    void init() {
        //初始化状态转移矩阵
        a.clear();
        for(int j=0;j<m;j++)a.mat[0][j]=K*(K-1);
        for(int i=1;i<m;i++)a.mat[i][i-1]=K;
        for(int j=m;j<=2*m;j++)a.mat[m][j]=K*(K-1);
        for(int i=m+1;i<=2*m;i++)a.mat[i][i-1]=K;
        a.mat[2*m][m-1]=K;
    }
    
    Mat operator * (Mat a, Mat b) {
        Mat c;
        for(int i=0;i<=2*m;i++){
            for(int j=0;j<=2*m;j++){
                for(int k=0;k<=2*m;k++){
                    c.mat[i][j]+=b.mat[i][k]*a.mat[k][j];
                    c.mat[i][j]%=MOD;
                }
            }
        }
        return c;
    }
    
    Mat operator ^ (Mat a, int k) {
        //初状态
        Mat c;
        c.mat[0][0]=1;
        //快速幂
        for(;k;k>>=1){
            if(k&1)c=c*a;
            a=a*a;
        }
        return c;
    }
    
    int main() {
        //freopen("data.in", "r", stdin);
            //初始化状态转移矩阵
            init();
            //矩阵快速幂,初始左矩阵不是单位矩阵,是初状态
            a = a^n;
        return 0;
    }
     
     
  • 相关阅读:
    插件制作入门
    Hank老师推荐的一些博客
    高级iOS工程师的博客
    查看一个文件是否支持64位 方法 ,[symbol(s) not found for architecture x86_64]相关
    ssh-keygen的使用方法及配置authorized_keys两台linux机器相互认证
    使用git在两台机器间同步代码
    scp远程拷贝命令
    后台启动程序并重定向输出信息脚本
    automake 工具的使用
    minigui启动过程
  • 原文地址:https://www.cnblogs.com/xuwangzihao/p/5806119.html
Copyright © 2020-2023  润新知