【BZOJ-1009】GT考试 KMP+DP+矩阵乘法+快速幂

1009: [HNOI2008]GT考试

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 2745  Solved: 1694
[Submit][Status][Discuss]

Description

  阿申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字。
他的不吉利数学A1A2...Am(0<=Ai<=9)有M位,不出现是指X1X2...Xn中没有恰好一段等于A1A2...Am. A1和X1可以为
0

Input

  第一行输入N,M,K.接下来一行输入M位的数。 N<=10^9,M<=20,K<=1000

Output

  阿申想知道不出现不吉利数字的号码有多少种,输出模K取余的结果.

Sample Input

4 3 100
111

Sample Output

81

HINT

Source

Solution

这个题非常的好

开始看范围,$10^{9}$显然O(n)都不能做啊,但是又像数位DP,所以肯定要优化,能优化到O(n)以下的只有矩乘快速幂优化DP了

实际上确实和数位DP非常累死,F[i][j]表示位数为i,最后匹配了j位的方案数,这样答案显然为$sum_{i=1}^{n}F[n][i]$

考虑KMP的next数组,分类讨论一下,搞到矩阵上,然后快速幂一下搞搞

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int n,m,p,next[110],an; char S[110];
struct Matrixnode
{
    int da[30][30];
    Matrixnode(){memset(da,0,sizeof(da));}
}a; 
Matrixnode Mul (Matrixnode A,Matrixnode B)
{
    Matrixnode C;
    for (int i=0; i<m; i++)
        for (int j=0; j<m; j++)
            for (int k=0; k<m; k++)
                C.da[i][j]=(C.da[i][j]+A.da[i][k]*B.da[k][j])%p;
    return C;
}
Matrixnode Pow (Matrixnode A,int x)
{
    Matrixnode re;
    for (int i=0; i<m; i++) re.da[i][i]=1;
    for (int i=x; i; i>>=1,A=Mul(A,A))
        if (i&1) re=Mul(re,A);
    return re;
}
void KMP_prework()
{
    for (int j=0,i=2; i<=m; i++)
        {
            while (j && S[i]!=S[j+1]) j=next[j];
            if (S[j+1]==S[i]) j++; next[i]=j;
        }
    for (int i=0; i<m; i++)
        for (int x,j=0; j<10; j++)
            {
                x=i;
                while (x && S[x+1]-'0'!=j) x=next[x];
                if (j==S[x+1]-'0') a.da[i][x+1]++; else a.da[i][0]++;
            }
}
int main()
{
    scanf("%d%d%d
",&n,&m,&p); scanf("%s",S+1);
    KMP_prework();
    Matrixnode ans; ans=Pow(a,n);
    for (int i=0; i<m; i++) an=(an+ans.da[0][i])%p;
    printf("%d
",an);
    return 0;
}

Matrixnode写起来怎么那么长,搞的码风丑死啦

原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5453407.html