BZOJ 1009--GT考試(KMP&DP&矩陣乘法)
阿新 • • 發佈:2017-10-23
color efi namespace highlight long 情況 ref urn scanf
RP++
題目鏈接:
http://www.lydsy.com/JudgeOnline/problem.php?id=1009
Solution
考慮DP。。。
dp [ i ] [ j ] 表示現在放完了 i 位,沒有出現不吉利數字,但是末尾已經與不吉利數字最多對應了j 位的情況的數量
狀態轉移方程。。。說起來很麻煩但很顯然
先對“不吉利數字”做KMP,然後就可以根據此時狀態進行DP。。
但是發現 i 這一維太大了。。。不論時間還是空間都是不允許的。。
於是要用矩陣乘法加速DP。。。
具體實現還是直接看代碼吧。。。。
代碼
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define M 1010
#define LL long long
#define mod 1000000007
using namespace std;
int n,m,p;
int nxt[M];
char s[25];
struct jz{
int x[22][22];
friend jz operator *(const jz &a,const jz &b){
jz tmp;
for(int i=0;i<m;i++)
for(int j=0;j<m;j++){
tmp.x[i][j]=0;
for(int k=0;k<m;k++)
tmp.x[i][j]=(tmp.x[i][j]+a.x[i][k]*b.x[k][j])%p;
}
return tmp;
}
}a,b;
void KMP(){
int f=0;
for(int i=2;i<=m;i++){
while(f>0&&s[f+1]!=s[i]) f=nxt[f];
if(s[f+1]==s[i]) f++;
nxt[i]=f;
}
for(int i=0;i<m;i++)
for(int j=‘0‘;j<=‘9‘;j++){
f=i;
while(f>0&&s[f+1]!=j) f=nxt[f];
if(s[f+1]==j) b.x[i][f+1]++;
else b.x[i][0]++;
}
}
void pow(){
while(n){
if(n&1) a=a*b;
n>>=1;
b=b*b;
}
}
int main(){
int ans=0;
scanf("%d%d%d",&n,&m,&p);
scanf("%s",s+1);
KMP();
for(int i=0;i<m;i++)
a.x[i][i]=1;
pow();
for(int i=0;i<m;i++)
ans=(ans+a.x[0][i])%p;
printf("%d\n",ans);
return 0;
}
This passage is made by Iscream-2001.
BZOJ 1009--GT考試(KMP&DP&矩陣乘法)