1. 程式人生 > >【轉載】BZOJ 1009 【HNOI2008】 GT考試

【轉載】BZOJ 1009 【HNOI2008】 GT考試

預處理 cstring bsp fin 枚舉 highlight 多少 spa 只需要

/*這道題因為有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取余的結果.

  這道題一眼看去像是一道容斥dp,仔細思考後發現其實普通的dp就可以做了。   我們令
fi,jfi,j表示準考證號確定了前i位,其中最後一段已經和不吉利串匹配了jj位的方案數。那麽,顯然我們只需要枚舉每一位選什麽數字即可。至於加了一位數字之後最後一段匹配了多少位,完全可以用kmpkmp來解決。因為kmpkmp算法中nextnext數組的含義就是不為整個串的前綴與後綴相等的最大長度。
  但是,這樣的復雜度是O(NM2)O(NM2)的。觀察發現,MM特別小,於是可以把轉移矩陣預處理出來,使用矩陣快速冪優化即可。   下面貼代碼:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
 
using namespace std;
typedef long long llg;
 
int n,m,k,nt[22],ans;
char s[22];
void gi(int &x){if(x>=k) x%=k;}
struct matrix{
    int w[23][23];
    matrix(){memset(w,0,sizeof(w));}
    void fu(){for(int i=0;i<m;i++) w[i][i]=1;}
    matrix operator * (const matrix &h)const{
        matrix a;
        for(int i=0;i<m;i++)
            for(int j=0;j<m;j++)
                for(int k=0;k<m;k++)
                    a.w[i][j]+=w[i][k]*h.w[k][j],gi(a.w[i][j]);
        return a;
    }
}A,Aa;
 
int getint(){
    int w=0;bool q=0;
    char c=getchar();
    while((c>‘9‘||c<‘0‘)&&c!=‘-‘) c=getchar();
    if(c==‘-‘) c=getchar(),q=1;
    while(c>=‘0‘&&c<=‘9‘) w=w*10+c-‘0‘,c=getchar();
    return q?-w:w;
}
 
matrix mi(matrix a,int b){
    matrix s; s.fu();
    while(b){
        if(b&1) s=s*a;
        a=a*a; b>>=1;
    }
    return s;
}
 
int main(){
    File("a");
    n=getint(); m=getint(); k=getint();
    scanf("%s",s+1);
    for(int i=2,j=0;i<=m;i++){
        while(j && s[j+1]!=s[i]) j=nt[j];
        if(s[j+1]==s[i]) j++;
        nt[i]=j;
    }
    for(int i=0,x;i<m;i++)
        for(int j=0;j<=9;j++){
            x=i;
            while(x && s[x+1]-‘0‘!=j) x=nt[x];
            if(s[x+1]-‘0‘==j) x++;
            if(x<m) A.w[i][x]++;
        }
    Aa=mi(A,n);
    for(int i=0;i<m;i++) ans+=Aa.w[0][i],gi(ans);
    printf("%d",ans);
}

  

【轉載】BZOJ 1009 【HNOI2008】 GT考試