1009: [HNOI2008]GT考试
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 2794 Solved: 1723
[ Submit][ Status][ Discuss]
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
111
Sample Output
81
HINT
Source
题解:这道题的暴力dp 与文本生成器一题是一样的。
f[i][j]表示的是原数列的第i位匹配到了trie树的第J个节点。
然后构造优化矩阵,如果当前节点是合法的并且他的儿子也是合法的,那么他就可以推他的儿子,所以在优化矩阵中A[I][CH[I][J]]=1.
然后A^N ,就是转移后的结果。
根据暴力DP我们可以发现,第一步的时候只有与0这个节点相连的节点才会被更新,所以初始矩阵是一个1×tot 的01矩阵。
最后再用初始矩阵,乘以A,将结果累加即为答案。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
int n,m,p,a[1000],tot;
int ch[200][26],fail[1003],isend[1000];
int f[2][1000],cnt;
int N;
struct data
{
int a[100][100];
}e;
void insert()
{
int now=0;
for (int i=1;i<=m;i++)
{
if (!ch[now][a[i]]) ch[now][a[i]]=++tot;
now=ch[now][a[i]];
}
isend[now]=1;
}
void makefail()
{
int now=0;
queue<int> p;
for (int i=0;i<=9;i++)
if (ch[now][i]) p.push(ch[now][i]);
while (!p.empty())
{
int now=p.front(); p.pop();
for (int i=0;i<=9;i++)
{
if (!ch[now][i])
{
ch[now][i]=ch[fail[now]][i];
continue;
}
int x=ch[now][i];
fail[x]=ch[fail[now]][i];
if (isend[fail[x]]) isend[x]=1;
p.push(x);
}
}
}
void clear(data &x)
{
for (int i=1;i<=N;i++)
for (int j=1;j<=N;j++)
x.a[i][j]=0;
}
void change(data &a,data b)
{
for (int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
a.a[i][j]=b.a[i][j];
}
data mul(data a,data b)
{
data c;
for (int i=1;i<=N;i++)
for (int j=1;j<=N;j++)
{
c.a[i][j]=0;
for (int k=1;k<=N;k++)
c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j]%p)%p;
}
return c;
}
data pow(data num,int x)
{
data ans; clear(ans);
for (int i=1;i<=N;i++) ans.a[i][i]=1;
data base; change(base,num);
while(x)
{
if (x&1) ans=mul(ans,base);
x>>=1;
base=mul(base,base);
}
return ans;
}
void build()
{
N=tot; clear(e);
for (int i=1;i<=tot;i++)
{
if (isend[i]) continue;
for (int j=0;j<=9;j++)
{
if (isend[ch[i][j]]) continue;
e.a[i][ch[i][j]]=1;
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&p);
char s[30]; scanf("%s",s+1);
for (int i=1;i<=m;i++)
a[i]=s[i]-'0';
insert();
for (int i=0;i<=9;i++)
if (!ch[0][i])
ch[0][i]=++tot;
makefail();
build();
data ans=pow(e,n-1);
for (int i=0;i<=tot;i++)
{
if (isend[i]) continue;
for (int j=0;j<=9;j++)
f[1][ch[i][j]]+=(i==0);
}
int t[100]; int sum=0;
for (int j=1;j<=N;j++)
{
t[j]=0;
for (int k=1;k<=N;k++)
t[j]=(t[j]+f[1][k]*ans.a[k][j]%p)%p;
sum=(sum+t[j])%p;
}
printf("%d\n",sum);
}