BZOJ 1009--GT考试(KMP&DP&矩阵乘法)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 1009--GT考试(KMP&DP&矩阵乘法)相关的知识,希望对你有一定的参考价值。
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&矩阵乘法)的主要内容,如果未能解决你的问题,请参考以下文章
[HNOI2008][bzoj1009] GT考试 [KMP+矩阵快速幂]