1. 程式人生 > >[HNOI2008]GT考試

[HNOI2008]GT考試

一行 time 個數 style 接下來 矩陣 pri problem put

1009: [HNOI2008]GT考試

Time Limit: 1 Sec Memory Limit: 162 MB Submit: 4024 Solved: 2452 [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 設$dp[i][j]$表示前i個字符,且後綴為不吉利數字的前綴的最長長度為j的方案數,那麽顯然$ans = \sum_{i=1}^{m-1}\ dp[n][i]$ 設$num[i][j]$為在長度為$i$的不吉利數字的前綴後加一個數使得後綴為不吉利數字的前綴的最長長度為$j$的方案數,$num$數組可以用kmp求出來 轉移為$dp[k][j] = \sum_{i = 1}^{m - 1}\ dp[k -1][i] * num[i][j]$
對於同一串不吉利數字$num$數組為常數,那麽可以利用矩陣加速遞推
#include <cstdio>
#include <cstring> 
const int maxm = 25;
int mod;
struct matrix{
    int n, m, num[maxm][maxm];
    matrix(){}
    matrix(int _n, int _m){
        n = _n;
        m = _m;
        memset(num, 0, sizeof num);
    }
    matrix operator
* (const matrix &a){ matrix b(n, a.m); for(int i = 0; i < n; i++) for(int j = 0; j < a.m; j++) for(int k = 0; k < m; k++) (b.num[i][j] += num[i][k] * a.num[k][j]) %= mod; return b; } }; matrix ksm(matrix a, int b){ matrix s(a.m, a.m); for(int i = 0; i < s.m; i++) s.num[i][i] = 1; while(b){ if(b & 1) s = s * a; b >>= 1; a = a * a; } return s; } int n, m; char A[maxm]; int p[maxm]; int main(){ scanf("%d %d %d", &n, &m, &mod); scanf("%s", A + 1); p[1] = 0; for(int j = 0, i = 2; i <= m; i++){ while(A[i] != A[j + 1] && j) j = p[j]; if(A[i] == A[j + 1]) j++; p[i] = j; } matrix ans(1, m), zy(m, m); for(int i = 0; i < m; i++) for(int j = 0; j <= 9; j++){ int k = i; while(k && A[k + 1] != j) k = p[k]; if(A[k + 1] == j) k++; if(k != m) zy.num[i][k]++; } ans.num[0][0] = 1; ans = ans * ksm(zy, n); int aa = 0; for(int i = 0; i < m; i++) (aa += ans.num[0][i]) %= mod; printf("%d\n", aa); return 0; }

[HNOI2008]GT考試