【BZOJ-1009】GT考试 KMP+DP+矩阵乘法+快速幂

1009: [HNOI2008]GT考试

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit:
2745  Solved: 1694
[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

Sample Output

81

HINT

Source

Solution

这个题非常的好

开始看范围,$10^{9}$显然O(n)都不能做啊,但是又像数位DP,所以肯定要优化,能优化到O(n)以下的只有矩乘快速幂优化DP了

实际上确实和数位DP非常累死,F[i][j]表示位数为i,最后匹配了j位的方案数,这样答案显然为$\sum_{i=1}^{n}F[n][i]$

考虑KMP的next数组,分类讨论一下,搞到矩阵上,然后快速幂一下搞搞

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int n,m,p,next[],an; char S[];
struct Matrixnode
{
int da[][];
Matrixnode(){memset(da,,sizeof(da));}
}a;
Matrixnode Mul (Matrixnode A,Matrixnode B)
{
Matrixnode C;
for (int i=; i<m; i++)
for (int j=; j<m; j++)
for (int k=; k<m; k++)
C.da[i][j]=(C.da[i][j]+A.da[i][k]*B.da[k][j])%p;
return C;
}
Matrixnode Pow (Matrixnode A,int x)
{
Matrixnode re;
for (int i=; i<m; i++) re.da[i][i]=;
for (int i=x; i; i>>=,A=Mul(A,A))
if (i&) re=Mul(re,A);
return re;
}
void KMP_prework()
{
for (int j=,i=; i<=m; i++)
{
while (j && S[i]!=S[j+]) j=next[j];
if (S[j+]==S[i]) j++; next[i]=j;
}
for (int i=; i<m; i++)
for (int x,j=; j<; j++)
{
x=i;
while (x && S[x+]-''!=j) x=next[x];
if (j==S[x+]-'') a.da[i][x+]++; else a.da[i][]++;
}
}
int main()
{
scanf("%d%d%d\n",&n,&m,&p); scanf("%s",S+);
KMP_prework();
Matrixnode ans; ans=Pow(a,n);
for (int i=; i<m; i++) an=(an+ans.da[][i])%p;
printf("%d\n",an);
return ;
}

Matrixnode写起来怎么那么长,搞的码风丑死啦

上一篇:MySQL在按照某个字段分组、排序加序号


下一篇:double类型的数值计算