BZOJ 1009: [HNOI2008]GT考试

Posted _patrick

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 1009: [HNOI2008]GT考试相关的知识,希望对你有一定的参考价值。

BZOJ 1009: [HNOI2008]GT考试

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

这一题显然是数位dp的老套路了,之前做过一个ac自动机多串的dp。
这只有一个串显然是用kmp了。但是n<=10^9需要考虑优化。
观察dp方程:

\(f[i][j]=\sum_{k=0}^{m-1}f[i-1][k]*a[k][j]\)

f[i][j]表示放到第i个后缀j~i为匹配串的前缀1~j。a[k][j]为加一个字母由k转移到j的放置方案数。
f显然是线性转移,可以使用矩阵快速幂优化,完美的过了本题。

Code

#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define rep(i,x) for(int i=head[x];i;i=e[i].next)
#define mem(a,x) memset(a,x,sizeof(a))
typedef long long LL;
typedef double DB;
using namespace std;
inline int read() {
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') f=(ch=='-')?-1:f,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+(ch-'0'),ch=getchar();return f*x;
}
const int SZ=1000010,INF=0x3f3f3f3f;
int n,m,mod,next[233];
char s[233];
void get_next() {
    int l=strlen(s);
    next[0]=next[1]=0;
    fo(i,1,l-1) {
        int j;
        for(j=next[i];j&&s[i]!=s[j];j=next[j]);
        next[i+1]=(s[i]==s[j])?j+1:0;
    }
}
struct matrix {
    int n,m,num[30][30];
    matrix(int a,int b):n(a),m(b) {memset(num,0,sizeof(num));}
};
matrix operator *(const matrix &a,const matrix &b) {
    matrix ans(a.n,b.m);
    fo(i,0,ans.n-1) fo(j,0,ans.m-1) fo(k,0,a.m-1)
        ans.num[i][j]=(ans.num[i][j]+(LL)a.num[i][k]*b.num[k][j]%mod)%mod;
    return ans;
}
matrix ksm(matrix a,int b) {
    matrix ans(a.n,a.m);
    fo(i,0,ans.n-1) ans.num[i][i]=1;
    for(;b;a=a*a,b>>=1) if(b&1) ans=ans*a;
    return ans;
}
int main() {
    freopen("1009.in","r",stdin);
    n=read(),m=read(),mod=read(),scanf("%s",s),get_next();
    matrix f(m,m);
    fo(i,0,m-1) fo(j,0,9) {
        int k;
        for(k=i;k&&s[k]!='0'+j;k=next[k]);
        if(s[k]=='0'+j) k++;
        if(k!=m) f.num[i][k]++;
    }
    matrix fn=ksm(f,n),a(1,m);
    a.num[0][0]=1;
    a=a*fn;
    int ans=0;
    fo(i,0,m-1) ans=(ans+a.num[0][i])%mod;
    printf("%d\n",ans);
    return 0;
}

以上是关于BZOJ 1009: [HNOI2008]GT考试的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ1009: [HNOI2008]GT考试

BZOJ 1009 [HNOI2008]GT考试

bzoj 1009: [HNOI2008]GT考试

BZOJ 1009 HNOI 2008 GT考试 递推+矩乘

bzoj1009 [HNOI2008]GT考试

BZOJ 1009: [HNOI2008]GT考试