【轉載】BZOJ 1009 【HNOI2008】 GT考試
阿新 • • 發佈:2018-03-11
預處理 cstring bsp fin 枚舉 highlight 多少 spa 只需要 fi,jfi,j表示準考證號確定了前i位,其中最後一段已經和不吉利串匹配了jj位的方案數。那麽,顯然我們只需要枚舉每一位選什麽數字即可。至於加了一位數字之後最後一段匹配了多少位,完全可以用kmpkmp來解決。因為kmpkmp算法中nextnext數組的含義就是不為整個串的前綴與後綴相等的最大長度。
但是,這樣的復雜度是O(NM2)O(NM2)的。觀察發現,MM特別小,於是可以把轉移矩陣預處理出來,使用矩陣快速冪優化即可。
下面貼代碼:
/*這道題因為有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就可以做了。 我們令#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考試