您的位置:首页 > 其它

bzoj1009: [HNOI2008]GT考试

2016-11-07 19:07 281 查看

题目

  http://www.lydsy.com/JudgeOnline/problem.php?id=1009

题解

  套路题。。然而模板打得并不熟练

  先把那个串建成AC自动机(是不是有点小题大做。。),然后DP,f[i][j]表示长度为i的串,匹配到了j这个节点的方案数。那么p=acamove(j,k)(k=0..9),f[i][j]就能更新f[i+1][p],矩阵中trans[j][p]++,然后矩阵快速幂就好了

  1A。

(后来补的):

  看了别人的题解发现我确实有点小题大做了。。可以不用ac自动机而改为KMP,但求trans数组并且矩阵乘法加速的套路还是一样。刚刚看到一个概念就是说如果一个递推式形如f[i][j]=k1*f[i-1][0]+k2*f[i-1][1]+...+km*f[i-1][m-1]就能用矩阵乘法加速DP。不知道有没有用,不过我挺喜欢这些总结性的东西的。

代码

//AC自动机上的DP+矩阵快速幂
#include <cstdio>
#include <algorithm>
#include <queue>
#define maxm 30
using namespace std;
int trie[maxm][15], N, M, K, fail[maxm], tail[maxm], tot=1;
queue<int> q;
struct matrix
{
int m[maxm][maxm], r, c;
int* operator[](int x){return m[x];}
}trans, f, one;
matrix operator*(matrix a, matrix b)
{
int i, j, k;
matrix t;
for(i=1;i<=a.r;i++)
for(j=1;j<=b.c;j++)
{
t[i][j]=0;
for(k=1;k<=a.c;k++)t[i][j]=(t[i][j]+a[i][k]*b[k][j])%K;
}
t.r=a.r,t.c=b.c;
return t;
}
matrix pow(matrix a, int b)
{
matrix t=a, ans=one;
for(;b;t=t*t,b>>=1)if(b&1)ans=ans*t;
return ans;
}
void ins(char *s)
{
int pos;
for(pos=1;*s!=-1;s++)pos=trie[pos][*s]?trie[pos][*s]:trie[pos][*s]=++tot;
tail[pos]=1;
}
void acabuild()
{
int f, i, u;
q.push(1);
while(!q.empty())
{
u=q.front(),q.pop();
for(i=0;i<=9;i++)
if(trie[u][i])
{
for(f=fail[u];f and !trie[f][i];f=fail[f]);
if(f)fail[trie[u][i]]=trie[f][i];
else fail[trie[u][i]]=1;
q.push(trie[u][i]);
}
}
}
int acamove(int pos, int x)
{
for(;pos and !trie[pos][x];pos=fail[pos]);
return pos?trie[pos][x]:1;
}
void input()
{
char s[maxm];
int i;
scanf("%d%d%d%s",&N,&M,&K,s);
for(i=0;s[i];i++)s[i]-=48;
s[i]=-1;
ins(s);
}
void make()
{
int i, j, p;
acabuild();
for(i=1;i<tot;i++)
for(j=0;j<=9;j++)trans[i][acamove(i,j)]++;
trans.r=trans.c=tot;
f.r=1,f.c=tot;
f[1][1]=1;
one.r=one.c=tot;
for(i=1;i<=tot;i++)one[i][i]=1;
}
int main()
{
int ans=0, i;
input();
make();
f=f*pow(trans,N);
for(i=1;i<=M;i++)ans=(ans+f[1][i])%K;
printf("%d\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: