BZOJ 1009: [HNOI2008]GT考试
Posted _patrick
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 1009: [HNOI2008]GT考试相关的知识,希望对你有一定的参考价值。
BZOJ 1009: [HNOI2008]GT考试
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
这一题显然是数位dp的老套路了,之前做过一个ac自动机多串的dp。
这只有一个串显然是用kmp了。但是n<=10^9需要考虑优化。
观察dp方程:
\(f[i][j]=\sum_{k=0}^{m-1}f[i-1][k]*a[k][j]\)
f[i][j]表示放到第i个后缀j~i为匹配串的前缀1~j。a[k][j]为加一个字母由k转移到j的放置方案数。
f显然是线性转移,可以使用矩阵快速幂优化,完美的过了本题。
Code
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define rep(i,x) for(int i=head[x];i;i=e[i].next)
#define mem(a,x) memset(a,x,sizeof(a))
typedef long long LL;
typedef double DB;
using namespace std;
inline int read() {
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') f=(ch=='-')?-1:f,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+(ch-'0'),ch=getchar();return f*x;
}
const int SZ=1000010,INF=0x3f3f3f3f;
int n,m,mod,next[233];
char s[233];
void get_next() {
int l=strlen(s);
next[0]=next[1]=0;
fo(i,1,l-1) {
int j;
for(j=next[i];j&&s[i]!=s[j];j=next[j]);
next[i+1]=(s[i]==s[j])?j+1:0;
}
}
struct matrix {
int n,m,num[30][30];
matrix(int a,int b):n(a),m(b) {memset(num,0,sizeof(num));}
};
matrix operator *(const matrix &a,const matrix &b) {
matrix ans(a.n,b.m);
fo(i,0,ans.n-1) fo(j,0,ans.m-1) fo(k,0,a.m-1)
ans.num[i][j]=(ans.num[i][j]+(LL)a.num[i][k]*b.num[k][j]%mod)%mod;
return ans;
}
matrix ksm(matrix a,int b) {
matrix ans(a.n,a.m);
fo(i,0,ans.n-1) ans.num[i][i]=1;
for(;b;a=a*a,b>>=1) if(b&1) ans=ans*a;
return ans;
}
int main() {
freopen("1009.in","r",stdin);
n=read(),m=read(),mod=read(),scanf("%s",s),get_next();
matrix f(m,m);
fo(i,0,m-1) fo(j,0,9) {
int k;
for(k=i;k&&s[k]!='0'+j;k=next[k]);
if(s[k]=='0'+j) k++;
if(k!=m) f.num[i][k]++;
}
matrix fn=ksm(f,n),a(1,m);
a.num[0][0]=1;
a=a*fn;
int ans=0;
fo(i,0,m-1) ans=(ans+a.num[0][i])%mod;
printf("%d\n",ans);
return 0;
}
以上是关于BZOJ 1009: [HNOI2008]GT考试的主要内容,如果未能解决你的问题,请参考以下文章