BZOJ1009 - [HNOI2008]GT考试
Description
给出一个长度为
Solution
矩阵乘法优化DP。
设12345
,则1234
结尾的5
),123
结尾的45
)…
注意至少!比如对于模式串12123
,结尾是1212
的串应该只属于
那么,如何构造由
121
的转移矩阵为:
12
结尾的串,无论在末尾加上什么数也不能变成以12
结尾的串。 12
结尾的串,无论在末尾加上什么数也不能变成以1
结尾的串。 12
结尾的串,在末尾加上023456789
这九个数能够变成不以1
或12
结尾的串。 1
结尾的串,在末尾加上2
这个数能够变成以12
结尾的串。 1
结尾的串,在末尾加上1
这个数能够变成以1
结尾的串。 1
结尾的串,在末尾加上03456789
这八个数能够变成不以1
或12
结尾的串。 …
可以看到第一行元素和是9,其他行元素和是10。因为差1位就形成模式串的话,补上那位就不合法啦。
初始状态
时间复杂度
O(m3logn) 。
Code
//[HNOI2008]GT考试
#include <cstdio>
#include <cstring>
int n,m,P; char s[30],s0[30];
struct matrix
{
int row,col,v[30][30];
matrix operator *(matrix b)
{
int p=row,q=col,r=b.col;
matrix c; c.row=p,c.col=r;
for(int i=1;i<=p;i++)
for(int j=1;j<=r;j++)
{
c.v[i][j]=0;
for(int k=1;k<=q;k++)
c.v[i][j]+=v[i][k]*b.v[k][j],c.v[i][j]%=P;
}
return c;
}
}x,y;
int pre(int L)
{
for(int i=1;i<=L;i++)
{
int j=i;
while(s[j-i+1]==s0[j]&&j<=L) j++;
if(j==L+1) return m-(L-i+1);
}
return m;
}
matrix pow(matrix a,int b)
{
matrix res; res.row=res.col=a.row;
for(int i=1;i<=res.row;i++)
for(int j=1;j<=res.col;j++)
res.v[i][j]=(i==j);
matrix t=a;
while(b>0)
{
if(b&1) res=res*t;
t=t*t; b>>=1;
}
return res;
}
int main()
{
scanf("%d%d%d",&n,&m,&P);
scanf("%s",s+1);
x.row=x.col=m;
for(int i=1;i<=m;i++)
{
memset(s0,0,sizeof s0);
for(int j=1;j<=m-i;j++) s0[j]=s[j];
for(char j='0';j<='9';j++) s0[m-i+1]=j,x.v[i][pre(m-i+1)]++;
}
x.v[1][0]=0;
x=pow(x,n);
y.row=1,y.col=m,y.v[1][m]=1; y=y*x;
int ans=0;
for(int i=1;i<=m;i++) ans+=y.v[1][i];
printf("%d\n",ans%P);
return 0;
}
P.S.
再这样咸鱼…会死…