【BZOJ 1009】 [HNOI2008]GT考试
来源:互联网 发布:java学生管理系统源码 编辑:程序博客网 时间:2024/05/22 12:50
【题目链接】:http://www.lydsy.com/JudgeOnline/problem.php?id=1009
【题意】
【题解】
网上有几个博客写得挺好的.
这里发一下链接;
这一篇有把大概怎么做写下来;
http://www.cnblogs.com/BLADEVIL/p/3483694.html
而下面这一篇提到的细节比较好;也讲得比较清楚些;
http://blog.csdn.net/cjk_cjk/article/details/43038377
大概的思路:
假设你现在扫描到了你的准考证号的第i位,同时不吉利数字匹配到了第j位;
也就是说准考证上:i-j+1..i和不吉利数字的1..j匹配好了;
接下来要确定第i+1位是什么;
这里把第i+1位换成第i位,原来的第i位就变成i-1位;
设f[i][j]表示:准考证号前i位中 后j位与不吉利数的前j位相同时,前i位的方案数
则有
f[i][j]=f[i-1][0]*a[0][j]+f[i-1][1]*a[1][j]+…+f[i-1][m-1]*a[m-1][j]
这里的a[k][j]表示的是前一位如果匹配到了第k位,然后想通过增加一个数字变成i个数字 ,然后匹配到第j位,问在第i位有多少个数字可以选择;
这个a数组可以预处理出来;
我们先考虑这个a数组的求法:
比如不吉利数字为
1231243
这里;
假设我们扫描到了第5个数字2;
那么我们就相当于让第i-1个数字匹配到了第5个数字;
然后问你第i个状态哪些状态能由这第5个数字接受到?
它的下一个状态应该可以接匹配到了第3和第6个数字;
即类似
*****12x
****12312x
可能用上面博客的例子好一点:
比如:还是假设不吉利数为123124,那么
f[i][3]=f[i-1][2]+f[i-1][5],因为 f[i-1][2]末尾的*****12不能是**12312,所以需要f[i-1][5]补充 ;
这里的”不能是**12312“可以用一个判重的东西搞出来;
那么像上面这样的a数组要怎么搞呢?
KMP算法!
具体的只能看程序了;
(你需要理解KMP算法的思路才能搞,不然会看得晕头转向);
然后N这么大;
你肯定得写个矩阵快速幂啦;
主要是因为a数组能够独立出来;
因为系数确定了;
所以能够用矩阵;
以后看到这种线性齐次递推式
都能写个矩阵优化;
(我也不知道线性齐次递推式是什么);
f[0][0]=1,f[0][1..m]=0;
最后把f[0][0..m-1]加起来就是答案了;
因为不能全部匹配到嘛.
下面这一段感觉写得很好吧。
/*f[i][j]的准确含义:1.f[i][j]表示的每种方案不仅与其后j位有关,还应保证不含不吉利数 2.为避免重复,f[i][j]表示的每种方案都不含长度大于j且与不吉利数的前缀相同 的后缀 否则就会出现:从1到m标号,不吉利数为123124时,f[i][2]计数的方案包含f[i][5]计数的方案 的情况 */
【完整代码】
#include <bits/stdc++.h>using namespace std;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define LL long long#define rep1(i,a,b) for (int i = a;i <= b;i++)#define rep2(i,a,b) for (int i = a;i >= b;i--)#define mp make_pair#define pb push_back#define fi first#define se second#define rei(x) scanf("%d",&x)#define rel(x) scanf("%lld",&x)typedef pair<int,int> pii;typedef pair<LL,LL> pll;const int dx[9] = {0,1,-1,0,0,-1,-1,1,1};const int dy[9] = {0,0,0,-1,1,-1,1,-1,1};const double pi = acos(-1.0);const int M = 30;struct juzhen{ int s[M][M]; juzhen() { memset(s,0,sizeof s); }};int n,m,mod,f[M],cf[300];char s[M];juzhen a,F;juzhen cheng(juzhen A,juzhen B){ juzhen c; rep1(i,0,m) rep1(j,0,m) rep1(k,0,m) c.s[i][j] = (c.s[i][j]+A.s[i][k]*B.s[k][j])%mod; return c;}juzhen ksm(juzhen A,int n){ if (n==1) return A; juzhen res = ksm(A,n>>1); juzhen t = cheng(res,res); if (n&1) t = cheng(t,A); return t;}int main(){ //freopen("F:\\rush.txt","r",stdin); rei(n),rei(m),rei(mod); scanf("%s",s+1); f[1] = f[2] = 1; rep1(i,2,m-1) { int j = f[i]; while (j > 1 && s[i]!=s[j]) j = f[j]; f[i+1] = (s[i]==s[j])?j+1:1; } int sum; rep1(i,0,m-1) { int j = i+1; sum = a.s[i][j] = 1; cf[s[j]] = i+1; while (j > 1) { j = f[j]; if (cf[s[j]]!=i+1) { cf[s[j]] = i+1; a.s[i][j] = 1; sum++; } } a.s[i][0] = 10-sum; } F.s[0][0] = 1; F = cheng(F,ksm(a,n)); int ans = 0; rep1(i,0,m-1) ans = (ans + F.s[0][i])%mod; printf("%d\n",ans); return 0;}
- BZOJ 1009: [HNOI2008]GT考试
- BZOJ-1009-GT考试-HNOI2008
- BZOJ 1009 [HNOI2008]GT考试
- 【BZOJ 1009】 [HNOI2008]GT考试
- BZOJ 1009 [HNOI2008] GT考试
- BZOJ 1009 [HNOI2008]GT考试
- 1009: [HNOI2008]GT考试
- 1009: [HNOI2008]GT考试
- BZOJ 1009([HNOI2008]GT考试-KMP+矩阵加速Dp)
- BZOJ KMP+矩阵快速幂 1009: [HNOI2008]GT考试
- BZOJ 1009 HNOI2008 GT考试 KMP算法+矩阵乘法
- BZOJ 1009: [HNOI2008]GT考试 AC自动机+矩阵快速幂
- BZOJ 1009 [HNOI2008]GT考试 AC自动机+矩阵乘法
- bzoj 1009: [HNOI2008]GT考试 KMP+矩阵乘法
- 【BZOJ】1009 [HNOI2008]GT考试 KMP+DP+矩阵优化
- 【BZOJ】1009 GT考试
- 【BZOJ】1009 GT考试
- 【BZOJ 1009】GT考试
- Apache安装(Linux)
- H264—MP4格式及在MP4文件中提取H264的SPS、PPS及码流
- c语言 求三角形面积升级版
- MySQL中group_concat函数,连接字段,多个值显示为一行
- MySQL的约束和索引
- 【BZOJ 1009】 [HNOI2008]GT考试
- valgrind 的使用简介
- Lock wait timeout exceeded; try restarting transaction
- C语言 求解二次函数
- cocos2dx-lua中带有‘\0’数据的字符串传递
- 加载顺序 ready onload onreadystatechange
- oj1094: A+B for Input-Output Practice (VII)
- C语言 输出字符01
- C语言字节对齐