1009: [HNOI2008]GT考试
来源:互联网 发布:js push array[0] 问题 编辑:程序博客网 时间:2024/05/14 21:34
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
题解
话说好像很久没有写过矩乘了。。
dp[i][j]表示身份证号的前i个数,最后j个数和不吉利数的前j位相同的合法情况数
dp[i][j] = ∑(dp[i-1][k]*p[k][j]) (0<=k<=m-1)
p[k][j]表示不吉利数前k个字符加上某个字符后最多能匹配不吉利数的前j个字符,问有多少种可添加字符
大概的思路就是这样,然而你直接写会TLE,我就写了一发
#include<cstdio>#include<cstring>const int N=25;int n,m,K;char ss[N];int g[N];void get (){ int i=1,j=0; g[1]=0; while (i<=m) { if (j==0||ss[i]==ss[j]) g[++i]=++j; else j=g[j]; }}int p[N][N];//不吉利的字符串当前匹配搭配第j位,加上一位可以到k位,这一位有多少中情况int f[2][N],now; int main(){ scanf("%d%d%d",&n,&m,&K); scanf("%s",ss+1); get(); for (int u=1;u<=m;u++) { for (int i=0;i<=9;i++)//我要填什么 { int t=u; while (t!=0&&ss[t]-'0'!=i) t=g[t]; p[u-1][t]++; } } for (int u=0;u<m;u++) for (int i=0;i<m;i++) p[u][i]%=K; now=0;f[0][0]=1; for (int u=1;u<=n;u++) { now=now^1; for (int i=0;i<m;i++)//匹配到了多少位 { f[now][i]=0; for (int k=0;k<m;k++) f[now][i]=(f[now][i]+f[now^1][k]*p[k][i]%K)%K; } } int ans=0; for (int u=0;u<m;u++) ans=(ans+f[now][u])%K; printf("%d\n",ans); return 0;}
那怎么办呢,我们发现,把DP看作第一个矩阵,然后p数组看作是第二个
你会神奇的发现,他可以使用矩阵快速幂优化。。
于是就可以了
#include<cstdio>#include<cstring>const int N=25;int n,m,K;char ss[N];int g[N];void get (){ int i=1,j=0; g[1]=0; while (i<=m) { if (j==0||ss[i]==ss[j]) g[++i]=++j; else j=g[j]; } }int p[N][N];//不吉利的字符串当前匹配搭配第j位,加上一位可以到k位,这一位有多少中情况int f[2][N],now;struct qq{ int f[30][30];//矩阵 friend qq operator *(qq a,qq b) { qq c; memset(c.f,0,sizeof(c.f)); for (int u=0;u<m;u++) for (int i=0;i<m;i++) for (int j=0;j<m;j++) c.f[u][i]=(c.f[u][i]+a.f[u][j]*b.f[j][i])%K; return c; }};qq lalal (qq a,int y){ if (y==1) return a; qq b=lalal(a,y/2); b=b*b; if (y%2!=0) b=b*a; return b;}int main(){ scanf("%d%d%d",&n,&m,&K); scanf("%s",ss+1); get(); for (int u=1;u<=m;u++) { for (int i=0;i<=9;i++)//我要填什么 { int t=u; while (t!=0&&ss[t]-'0'!=i) t=g[t]; p[u-1][t]++; } } qq b; for (int u=0;u<m;u++) for (int i=0;i<m;i++) b.f[u][i]=p[u][i]%K; b=lalal(b,n); int ans=0; for (int u=0;u<m;u++) ans=(ans+b.f[0][u])%K; printf("%d\n",ans); return 0;}
另外,第一次用friend,感觉真好用。。
阅读全文
0 0
- 1009: [HNOI2008]GT考试
- 1009: [HNOI2008]GT考试
- BZOJ 1009: [HNOI2008]GT考试
- BZOJ-1009-GT考试-HNOI2008
- BZOJ 1009 [HNOI2008]GT考试
- 【BZOJ 1009】 [HNOI2008]GT考试
- BZOJ 1009 [HNOI2008] GT考试
- BZOJ 1009 [HNOI2008]GT考试
- bzoj1009: [HNOI2008]GT考试
- [HNOI2008]GT考试
- [bzoj1009][HNOI2008]GT考试
- BZOJ1009 HNOI2008 GT考试
- 【bzoj1009】[HNOI2008]GT考试
- [BZOJ1009][HNOI2008]GT考试
- 【HNOI2008】GT考试
- [HNOI2008] [BZOJ1009] GT考试
- 【BZOJ1009】【HNOI2008】GT考试
- BZOJ1009: [HNOI2008]GT考试
- js传参数的时候用[],而不是用.
- HDU 6129 Just do it(杨辉三角+lucas \ 记忆化dp)
- javaI的O
- 底部导航栏:利用viewpager实现Android底部标题栏
- reason: '-[__NSArrayM enqueue:]: unrecognized selector sent to instance 0x14d59dc0'
- 1009: [HNOI2008]GT考试
- PAT 1009 说反话
- c++ 函数返回引用
- C# 线程这个烦人的join
- Spring Boot 搭建以及集成 StringRedisTemplate
- 组合数取模
- operator 的用法
- 怪盗基德的挑战书||HDU4552
- Shell标准输出、标准错误 >/dev/null 2>&1