您的位置:首页 > 其它

Bzoj1009 [HNOI2008]GT考试

2016-07-17 11:22 302 查看

 

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 2872  Solved: 1769

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

HINT

Source

 

动归。

用f[i][j]表示填到第i位,不吉利串匹配到第j位的方案数,动态规划。

kmp预处理出不吉利串的next数组,这样就可以利用next,在填每一位数时进行状态转移(如果填的下一个数能匹配,则匹配长度++,否则跳到next)

之后用矩阵乘法计算总方案数

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int n,m,k;
int next[500];
char ch[30];
int a[30][30],b[30][30];
void getnext(char s[]){
next[0]=next[1]=0;
int i,j;
for(i=2,j=0;i<=m;i++){
while(j && s[j+1]!=s[i])j=next[j];
if(s[j+1]==s[i])j++;
next[i]=j;
}
return;
}
void multi(int a[30][30],int b[30][30],int ans[30][30],int mod){
int tmp[30][30];
int i,j,k;
for(i=0;i<m;i++)
for(j=0;j<m;j++){
tmp[i][j]=0;
for(k=0;k<m;k++)
tmp[i][j]=(tmp[i][j]+a[i][k]*b[k][j])%mod;
}
for(i=0;i<m;i++)
for(j=0;j<m;j++)
ans[i][j]=tmp[i][j];
}
int main(){
scanf("%d%d%d",&n,&m,&k);
scanf("%s",ch+1);
getnext(ch);
int i,j;
//
for(i=0;i<m;i++)
for(j=0;j<=9;j++){
int t=i;
while(t && ch[t+1]-'0'!=j) t=next[t];
if(ch[t+1]-'0'==j)t++;
if(t!=m)b[t][i]=(b[t][i]+1)%k;//转移
}
//
for(i=0;i<m;i++)a[i][i]=1;
while(n){
if(n&1)multi(a,b,a,k);
multi(b,b,b,k);
n>>=1;
}
int sum=0;
for(i=0;i<m;i++)sum=(sum+a[i][0])%k;//累计
printf("%d\n",sum);
return 0;
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: