zoukankan      html  css  js  c++  java
  • BZOJ 1009: [HNOI2008]GT考试

    二次联通门 : BZOJ 1009: [HNOI2008]GT考试

    /*
        BZOJ 1009: [HNOI2008]GT考试
        
        Kmp预处理 + 矩阵优化dp
        
        dp[i][j] 表示第i个号码匹配到了第j个不吉利的数字的方案数 
        
        S[x][y]为dp[i - 1][x] 转移到 dp[i][y]的方案数
        
        S[x][y]就是长度为x的一个前缀,加上一个数字后, 后缀的最长长度为y的前缀匹配
        能加的数字有多少种 
         
        后转为矩阵就好了 
        
        最烦的就是字符串0,1号位的选择问题了。。。 
        
    */
    #include <cstring>
    #include <cstdio>
     
    #define Max 100
     
    void read (int &now)
    {
        now = 0;
        register char word = getchar ();
        while (word < '0' || word > '9')
            word = getchar ();
        while (word >= '0' && word <= '9')
        {
            now = now * 10 + word - '0';
            word = getchar ();
        }
    }
     
    int Mod;
    int N, M;
     
     
    char line[Max];
     
    struct Martix_Data
    {
        int data[Max][Max];
         
        Martix_Data operator * (const Martix_Data &now) const
        {
            Martix_Data res;
             
            for (register int i = 0; i < M; i ++)
                for (register int j = 0; j < M; j ++)
                {
                    res.data[i][j] = 0;
                     
                    for (register int k = 0; k < M; k ++)
                        res.data[i][j] = (res.data[i][j] + this->data[i][k] * now.data[k][j]) % Mod;
                }
                 
            return res;
        }
         
    };
     
    Martix_Data S;
    Martix_Data Answer;
     
    Martix_Data operator ^ (Martix_Data now, int P)
    {
        Martix_Data res = Answer;
         
        for (; P; now = now * now, P >>= 1)
            if (P & 1)
                res = now * res;
         
        return res;
    }
      
    int next[Max];
     
    void Kmp_Prepare (char *__line)
    {
         
        int pos = 0;
        for (int i = 2; i <= M; i ++)
        {
            for (; pos && __line[pos + 1] != __line[i]; )
                pos = next[pos];
             
            if (__line[pos + 1] == __line[i])
                pos ++;
            next[i] = pos;
        }
         
        for (int i = 0, pos; i < M; i ++)
            for (char j = '0'; j <= '9'; j ++)
            {
                 
                for (pos = i; pos && __line[pos + 1] != j; )
                    pos = next[pos];
                     
                if (j == __line[pos + 1])
                    S.data[i][pos + 1] ++;
                else
                    S.data[i][0] ++;
            }
    }
     
    int main (int argc, char *argv[])
    {
        
        read (N);
        read (M);
        read (Mod);
         
        scanf ("%s", line + 1);
         
        Kmp_Prepare (line);
     
        for (int i = 0; i < M; i ++)
            Answer.data[i][i] = 1;
             
        Answer = S ^ N;
         
        int Total = 0;
        for (int i = 0; i < M; i ++)
            Total = (Total + Answer.data[0][i]) % Mod;
             
        printf ("%d", Total);
     
        return 0;
    }
  • 相关阅读:
    融云技术分享:全面揭秘亿级IM消息的可靠投递机制
    企业微信的IM架构设计揭秘:消息模型、万人群、已读回执、消息撤回等
    喜马拉雅亿级用户量的离线消息推送系统架构设计实践
    uni-app 项目使用 npm 包中的小程序自定义组件
    Leetcode563. 二叉树的坡度
    vue看源码遇到 报错
    windows使用
    mysql 显示行号
    从优秀到卓越
    【面经】阿里蚂蚁金服22秋招-Java后端
  • 原文地址:https://www.cnblogs.com/ZlycerQan/p/7074000.html
Copyright © 2011-2022 走看看