您的位置:首页 > 其它

BZOJ1009: [HNOI2008]GT考试 矩阵快速幂+kmp+dp

2017-07-09 20:34 423 查看
这个题你发现打暴力的话可以记忆化搜素加剪枝,那么意味着可以递推,我们搜的话就是1010^9我们就往下匹配遇到匹配成功就return,那么我们可以想一下什么决定了状态,我们考虑kmp的过程,对于我们目前匹配到的距离,下一次在匹配时不会用他之后的字符,那么只要我们知道匹配到的距离和已匹配长度就行了,那么我们考虑状态的转移,我们由于要像kmp那样匹配于是我们只要知道在匹配到k位时往下走一个数时匹配到哪,算出a[k][j](在k时到j的方案数),那么新的f[i][j]=∑f[i-1][k]*a[k][j],这里用到了对口遗传的思想,对于舍去的状态,我们不继承就是舍去了

至于钜乘(:••)去某位大佬博客

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int n,m,k;
char s[50];
int next[50];
int a[50][50],b[50][50],temp[50][50];
inline void kmp()
{
a[m-1][m-0]+=1;
a[m-0][m-0]+=9;
for(int i=1,K=0;i<m;i++)
{
while(K&&s[K]!=s[i])
K=next[K-1];
if(s[K]==s[i])
K++;
next[i]=K;
for(int j=0;j<=9;j++)
{
if(j+48==s[i])
{
a[m-i-1][m-i]+=1;
continue;
}
int l=next[i-1];
while(l&&s[l]!=j+48)
l=next[l-1];
if(s[l]==j+48)
l++;
a[m-l][m-i]+=1;
}
}
}
inline void Init()
{
scanf("%d%d%d%s",&n,&m,&k,s);
kmp();
}
inline void multi(int x[][50],int y[][50],int len)
{
memset(temp,0,sizeof(temp));
for(int i=1;i<=m;i++)
for(int j=1;j<=len;j++)
for(int l=1;l<=m;l++)
temp[i][j]=(temp[i][j]+y[i][l]*x[l][j])%k;
for(int i=1;i<=m;i++)
for(int j=1;j<=len;j++)
x[i][j]=temp[i][j];
}
inline void work()
{
b[m][1]=1;
while(n)
{
if(n&1)multi(b,a,1);
n>>=1;
multi(a,a,m);
}
}
inline void print()
{
int ans=0;
for(int i=1;i<=m;i++)
ans+=b[i][1];
ans%=k;
printf("%d",ans);
}
int main()
{
Init();
work();
print();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: