[HNOI2008]GT考试

题目描述

阿申准备报名参加 GT 考试,准考证号为 N 位数X1,X2Xn(0Xi9),他不希望准考证号上出现不吉利的数字。 他的不吉利数学A1,A2Am(0Ai9) 有 M位,不出现是指 X1,X2Xn 中没有恰好一段等于 A1,A2Am,A1X1 可以为 0

输入输出格式

输入格式:

 

第一行输入N,M,K.接下来一行输入M位的数

 

输出格式:

 

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

 

输入输出样例

输入样例#1: 
4 3 100
111
输出样例#1: 
81

说明

N≤10^9,M≤20,K≤1000

 

一些思路:

一道DP&&矩阵快速幂的题

首先,我们用DP式子表示出这道题所要求的值

设dp[i][j]表示X串前i位后缀匹配了A串的前j位,g[i][j]表示从匹配A串前i位变到前j位的方案数,没有就是0

易知,$dp[i][j]=\sum\limits_{k=0}^{m-1} dp[i-1][k]*g[k][j]$

答案即为$\sum\limits_{i=0}^{m-1} dp[n-1][i]$

我们会发现这是一个矩阵乘幂的式子

然后用矩阵快速幂乱搞一通即可

弱弱的说一句,其实我觉得这道题的预处理g[i][j]也蛮难的

上代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dwn(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
int a[50][50],m,n,mod,k,zlk[50][50],ans[50][50],sum,haha;
char ch[50];
void check(int x,int y){
    if(x+1<y || (ch[x+1]==ch[y] && y<x+1)) return;
    rep(i,1,y-1){
        if(ch[i]!=ch[x-y+1+i]) return;
    }
    rep(i,y+1,m-1) if(a[x][i] && ch[i]==ch[y]) return;
    a[x][y]=1;
    return;
}
void ksm(){
    while(k){
        if(k&1){
            memset(zlk,0,sizeof(zlk));
            rep(i,0,m-1) rep(j,0,m-1) rep(k,0,m-1) zlk[i][j]+=ans[i][k]*a[k][j],zlk[i][j]%=mod;
            rep(i,0,m-1) rep(j,0,m-1) ans[i][j]=zlk[i][j];
        }
        memset(zlk,0,sizeof(zlk));
        rep(i,0,m-1) rep(j,0,m-1) rep(k,0,m-1) zlk[i][j]+=a[i][k]*a[k][j],zlk[i][j]%=mod;
        rep(i,0,m-1) rep(j,0,m-1) a[i][j]=zlk[i][j];
        k>>=1;
    }
}
bool wk(int x,int y){
    rep(i,1,x+1){
        bool c=0;
        rep(j,1,i-1) if(ch[j]!=ch[x-i+j+1]){c=1; break;}
        if(!c && y+'0'==ch[i]) return 0;
    }
    return 1;
}
int main(){
    scanf("%d%d%d",&k,&m,&mod);
    cin>>ch+1;
    rep(i,1,m-2) dwn(j,m-1,1)  check(i,j);
    dwn(j,m-1,1){
        check(m-1,j);
        if(a[m-1][j] && ch[j]==ch[m]) a[m-1][j]=0;
    }
    dwn(i,m-1,0) rep(j,0,9) if(wk(i,j)) a[i][0]++;
    a[0][1]=1;
    rep(i,0,m-1) ans[i][i]=1;
    ksm();
    rep(i,0,m-1) sum+=ans[0][i],sum%=mod;
    printf("%d",sum);
    return 0;
}

  

posted @   niolle  阅读(396)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示