列表

详情


NC20064. [HNOI2008]GT考试

描述

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

输入描述

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

输出描述

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

示例1

输入:

4 3 100 
111

输出:

81

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++11(clang++ 3.9) 解法, 执行用时: 5ms, 内存消耗: 376K, 提交时间: 2020-07-19 16:48:07

#include <cstring>
#include <iostream>

using namespace std;
const int N=25;

int n, m, mod;
char p[N];
int ne[N];
int a[N][N];

void mul(int c[][N], int a[][N], int b[][N]){
    static int t[N][N];
    memset(t, 0x00, sizeof t);
    for(int i=0; i<m; ++i)
        for(int j=0; j<m; ++j)
            for(int k=0; k<m; ++k)
                t[i][j]=(t[i][j]+a[i][k]*b[k][j])%mod;
    memcpy(c, t, sizeof t);
}

int qmi(int k){
    int f[N][N]={1};
    while(k){
        if(k&0x01) mul(f, f, a);
        mul(a, a, a);
        k>>=1;
    }
    int ans=0;
    for(int i=0; i<m; ++i) ans=(ans+f[0][i])%mod;
    return ans;
}

int main(){
    cin>>n>>m>>mod;
    cin>>p;
    
    // kmp
    for(int i=1, j=0; i<m; ++i){
        while(j && p[i]!=p[j]) j=ne[j-1];
        if(p[i]==p[j]) ++j;
        ne[i]=j;
    }
    
    // 初始化a[i][j]
    for(int j=0; j<m; ++j){
        for(int c='0'; c<='9'; ++c){
            int k=j;
            while(k && p[k]!=c) k=ne[k-1];
            if(p[k]==c) ++k;
            if(k<m) a[j][k]++;
        }
    }
    
    cout<<qmi(n)<<endl;
    return 0;
}

上一题