1. 程式人生 > >【矩陣加速】【數論】【KMP】[BZOJ1009][HNOI2008]GT考試

【矩陣加速】【數論】【KMP】[BZOJ1009][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位的數。 100%資料N<=10^9,M<=20,K<=1000 40%資料N<=1000 10%資料N<=6

Output

阿申想知道不出現不吉利數字的號碼有多少種,輸出模K取餘的結果.

Sample Input

4 3 100
111

Sample Output

81

題目分析

首先我們令dp(i,j)表示當前我們列舉到第i位的時候我們列舉的字尾最長和不吉利的字串的字首已經匹配了j個的時候的方案數量,那麼我們的答案就是

i=0m1dp(n,i)那麼我們可以發現我們令p(i,j)表示從不吉利的字串第i個字元後新增一個數字就可以從i個匹配變成j個匹配的可以填寫的數字的個數那麼我們顯然有dp(i,j)=k=0m1(dp(i1,k)×p(k,j))那麼我們的p顯然可以進行預處理,那麼我們發現p是可以表示成一個矩陣的同時我們發現dp也可以表示成一個矩陣那麼我們顯然有DPi=DPi1×P那麼我們就有DPn=DPn1
×P=DP0×Pn
使用矩陣加速進行優化

程式碼

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int MAXN = 22;
int MOD, Fail[MAXN+10];
char s[MAXN+10];
struct Matrix {
    int Ma[MAXN+10][MAXN+10], n, m;
    void Clear(int u, int un=0, int um=0){
        n = un, m = um;
        for
(int i=0;i<un;i++) for(int j=0;j<um;j++) Ma[i][j] = 0; if(u) for(int i=0;i<un;i++) Ma[i][i] = 1; } Matrix operator* (const Matrix& ma) { Matrix ret ; ret.Clear(0, n, m); for(int i=0;i<n;i++){ for(int j=0;j<ma.m;j++){ for(int k=0;k<ma.n;k++){ ret.Ma[i][j] += Ma[i][k] * ma.Ma[k][j]; ret.Ma[i][j] %= MOD; } } } return ret; } }; Matrix Mpow(Matrix m, int p){ Matrix ret; if(p == 0){ ret.Clear(1, 2, 2); return ret; }else if(p == 1) return m; ret = Mpow(m, p/2); if(p%2 == 0) return ret * ret; return (ret * ret) * m; } int main(){ int n, m; scanf("%d%d%d", &n, &m, &MOD); scanf("%s", s+1); Matrix mtr; mtr.Clear(0, m, m); mtr.Ma[0][0] = 9; mtr.Ma[0][1] = 1; for(int i=1;i<m;i++){ int us = Fail[i]; while(us){ if(s[us+1] == s[i+1]) break; us = Fail[us]; } if(s[us+1] == s[i+1]) Fail[i+1] = us+1; else Fail[i+1] = 0; for(int j=0;j<=9;j++){ int u = i; while(u&&s[u+1] != j+'0') u = Fail[u]; if(s[u+1] == j+'0') mtr.Ma[i][u+1] = (mtr.Ma[i][u+1] + 1) % MOD; else mtr.Ma[i][0] = (mtr.Ma[i][0] + 1) % MOD; } } Matrix ans = Mpow(mtr, n); int anst = 0; for(int i=0;i<m;i++) anst = (anst + ans.Ma[0][i]) % MOD; printf("%d\n", (anst+MOD)%MOD); return 0; }