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;
}
原文地址:https://www.cnblogs.com/ZlycerQan/p/7074000.html