• bzoj 做起走 -- bzoj 1009 GT 考试


      现在每次做一道bzoj上的题,整个人都感觉升华了。。。

      先是在网上各种搜题解。要么只有代码,要么有点讲解看不懂,对于从来没有耐心看完别人代码的我,只能一篇一篇的翻。。然后终于在某2011级同学的某段话中找到了灵感,把它给A了。

      我还是好好记录一下这道题的做题过程,不要又被其他人喷“只有做过的人才看得懂了!”

      首先说说这道题的思路吧:dp+矩阵优化。dp虽然不那么明显,但是做过了ac自动机上的dp之后也看得出来——kmp上的dp。具体怎么想到是dp的只能说是个人经验问题,做过一遍就容易做出来了。那么dp是什么呢?这种就跟ac自动机上的问题是一类的题,不过只有一个串来匹配,就kmp预处理咯。然后用一个二维的dp——f[i][j],i表示现在做到了第几位,j表示填完第i位后剩下了匹配到第几位。那么怎么转移呢?我们想,对于i-1转移到i位,其实和i是多少无关,i只和你转移是要加的那个值有关系,真真有关系的是i-1的已经匹配到了第j位。也就是说,每一次转移的,其实是一样的,也就是说我们可以预处理出i-1的j转移到i,然后存下来。

      所以转移方程: f[i][j] = f[i-1][0]*pre[0][j] + f[i-1][1]*pre[1][j] + f[i-j][2]*pre[2][j] + ...... f[i-1][m-1]*pre[m-1][j];(没有f[i-1][m]是因为这种情况是不合法的)

      那么怎么求出这样的处理呢? 使用kmp的next数组,从i位置开始,然后开始枚举第i+1位的数字开始向后匹配,然后找到可以匹配的最大的那个位置,基本写法参照kmp的匹配。每找到某一个位置,把那个位置的+1即可。

      但n是10^9,然后一看这个递推式子,就是矩阵乘法的形式啊!所以直接矩阵快速幂吧!

      顺便一说,归纳一下矩阵快速幂的基本的题型:转移方程中的系数在多次转移中不改变,且递推式是一阶的,然后一看数据特别大的,就可以考虑了。

      code:

      

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int maxn = 22;
    
    int n,m,mod;
    int str[maxn];
    int next[maxn];
    
    struct mtr{
        int mx[maxn][maxn];
        mtr(){memset(mx,0,sizeof(mx));}
    }modu;
    
    void self_build(){
        next[1] = 0;
        int j = next[1];
        for(int i = 2; i <= m; i++){
            while(j && str[j+1] != str[i]) j = next[j];
            if(str[j+1] == str[i]) j++;
            next[i] = j;
        }
    }
    
    mtr cf(mtr a, mtr b,int xm,int xn,int xk){
        mtr c;
        for(int i = 0; i < xm; i++)
            for(int j = 0; j < xk; j++)
                for(int k = 0;k < xn; k++){
                    c.mx[i][j] = (c.mx[i][j]%mod+((a.mx[i][k]%mod) * (b.mx[k][j])%mod)%mod)%mod;
                }
        return c;
    }
    
    mtr qpow(mtr a,int len,int b){
        mtr tmp;
        mtr re;
        for(int i = 0;i < len; i++)
            for(int j = 0; j < len; j++)
                tmp.mx[i][j] = a.mx[i][j];
        for(int i = 0; i < len; i++)
            re.mx[i][i] = 1;
        while(b){
            if(b&1) re = cf(re,tmp,len,len,len);
            tmp = cf(tmp,tmp,len,len,len);
            b >>= 1;
        }
        return re;
    }
    
    int fans;
    
    mtr ans;
    
    int main(){
        //freopen("cs.in","r",stdin);
        scanf("%d%d%d",&n,&m,&mod);
        getchar();
        for(int i = 1; i <= m; i++){
            str[i] = getchar() - '0';
        }
        self_build();
        for(int i = 0; i < m; i++){
            for(int j = 0;j <= 9; j++){
                int tmp = i;
                while(tmp && str[tmp+1] != j) tmp = next[tmp];
                if(str[tmp+1] == j) modu.mx[i][tmp+1] = (modu.mx[i][tmp+1]+1)%mod;
                else modu.mx[i][0] = (modu.mx[i][0]+1)%mod;
            }
        }
        ans.mx[0][0] = 1;
        modu = qpow(modu,m,n);
        ans = cf(ans,modu,1,m,m);
        fans = 0;
        for(int i = 0; i < m; i++)
            fans = (fans%mod + ans.mx[0][i]%mod)%mod;
        printf("%d",fans);
        return 0;
    }
    

     顺便再说一句,矩阵可以套在struct里面,好写些,具体可参见代码。

  • 相关阅读:
    C# 数据为空,不能对NULL调用此方法或属性的解决办法
    Hadoop开启后jps显示只有jps
    Ubuntu中eclipse端口被占
    Ubuntu在终端执行命令时出现的错误
    sudo passwd root输入普通用户密码后显示用户不再sudoers文件中
    周总结(4.4)
    《构建之法》读后感(三)
    周总结(3.28)
    软件工程团队项目介绍
    解决phpstudy中nginx服务器运行项目报错404问题
  • 原文地址:https://www.cnblogs.com/ianaesthetic/p/3714216.html
Copyright © 2020-2023  润新知