1. 程式人生 > >【刷題】BZOJ 3262 [HNOI2008]GT考試

【刷題】BZOJ 3262 [HNOI2008]GT考試

gpo operator max markdown 一位 枚舉 return 思想 設計

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

Solution

這題還是很無奈的

按照數位dp的思想依次考慮每一位上的數字,考慮設計dp,\(f[i][j]\) 代表考慮完第 \(i\) 位之後,後 \(j\) 位與不吉利數字的前 \(j\) 位相同的方案數
那麽最後答案為 \(ans=\sum_{i=0}^{m-1}f[n][i]\)
現在新加進來一個數,對之前的相同的 \(j\) 位造成的影響會有三種情況:

  1. 延長原有的 \(j\) 位,變成 \(j+1\)
  2. 直接把原有的 \(j\) 位打回0位
  3. 把原來的 \(j\) 位變短到一個位置,而這個位置,你會發現正好是KMP中求的fail/next數組

那麽,\(f[i][j]=f[i-1][j-1]+\sum_{k=1}^mf[i-1][k]*[next[k]=j-1]\)


再進一步,\(f[i][j]=\sum_{k=0}^{m-1}f[i-1][k]*a[k][j]\),其中 \(a[k][j]\) 代表從匹配好 \(k\) 位變成匹配 \(j\) 位的方案數
對於 \(a\) 數組,先KMP求出fail/next數組,然後直接枚舉每個位置上的每個數,相當於暴力求得
對於 \(f\) 數組,看上面的式子難道不眼熟嗎,這東西顯然可以矩陣快速冪優化
然後答案就出來了
註意一下每個人的KMP寫法都不一樣,求的fail/next數組也會有所不同,但只要能達到效果就可以了,不同的寫法最後算 \(a\) 的時候,細節略有不同

#include<bits/stdc++.h>
#define ll long long #define db double #define ld long double const int MAXM=400+5; int n,m,Mod,ans,nexts[MAXM]; char s[MAXM]; struct Matrix{ int a[MAXM][MAXM]; inline void init() { memset(a,0,sizeof(a)); } inline Matrix operator * (const Matrix &A) const { Matrix B; for(register int i=0;i<m;++i) for(register int j=0;j<m;++j) { B.a[i][j]=0; for(register int k=0;k<m;++k)(B.a[i][j]+=(a[i][k]*A.a[k][j]))%=Mod; } return B; }; }; Matrix A,B; template<typename T> inline void read(T &x) { T data=0,w=1; char ch=0; while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar(); if(ch=='-')w=-1,ch=getchar(); while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar(); x=data*w; } template<typename T> inline void write(T x,char c='\0') { if(x<0)putchar('-'),x=-x; if(x>9)write(x/10); putchar(x%10+'0'); if(c!='\0')putchar(c); } template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);} template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);} template<typename T> inline T min(T x,T y){return x<y?x:y;} template<typename T> inline T max(T x,T y){return x>y?x:y;} inline void KMP() { nexts[0]=-1; for(register int i=1;i<m;++i) { int j=nexts[i-1]; while(s[i]!=s[j+1]&&j>=0)j=nexts[j]; if(s[i]==s[j+1])nexts[i]=j+1; else nexts[i]=-1; } } inline void init() { KMP(); for(register int i=0;i<m;++i) for(register int j='0';j<='9';++j) { int k=i; while(k&&s[k]!=j)k=nexts[k-1]+1; if(s[k]==j)k++; if(k!=m)B.a[i][k]++; } } inline Matrix Fast_Matrix(int k) { Matrix res; res.init(); res=B; --k; while(k) { if(k&1)res=res*B; B=B*B; k>>=1; } return res; } int main() { read(n);read(m);read(Mod); A.init();B.init(); scanf("%s",s); init(); A.a[0][0]=1; B=Fast_Matrix(n); A=A*B; for(register int i=0;i<m;++i)(ans+=A.a[0][i])%=Mod; write(ans,'\n'); return 0; }

【刷題】BZOJ 3262 [HNOI2008]GT考試