[BZOJ1009][HNOI2008]GT考试(AC自动机+dp+矩阵优化)
2016-05-24 07:28
411 查看
题目描述
传送门题解
40%的数据和BZOJ1030文本生成器是一样的:f[i][j]表示准考证上第i位数和trie树上编号为j的节点匹配,不出现不吉利数字的方案数.考虑矩阵优化。目标矩阵表示了f中一维的状态。如果点i可以转移到ch[i][k],那么在转移矩阵的第i行第ch[i][k]列置1.判断是否成立的方法还是fail树。
代码
暴力dp#include<iostream> #include<cstring> #include<cstdio> #include<queue> using namespace std; const int max_n=1005; const int max_m=105; int n,m,Mod,ans,tot; char s[max_n]; int f[max_n][max_m]; int ch[max_m][20],fail[max_m];bool is_end[max_m]; queue <int> q; inline void insert() { int now=0; for (int i=0;i<m;++i) { int x=s[i]-'0'; if (!ch[now][x]) ch[now][x]=++tot; now=ch[now][x]; } is_end[now]=true; } inline void make_fail() { while (!q.empty()) q.pop(); for (int i=0;i<=9;++i) if (ch[0][i]) q.push(ch[0][i]); while (!q.empty()) { int now=q.front(); q.pop(); for (int i=0;i<=9;++i) { if (!ch[now][i]) { ch[now][i]=ch[fail[now]][i]; continue; } int x=ch[now][i]; fail[x]=ch[fail[now]][i]; if (is_end[fail[x]]) is_end[x]=true; q.push(x); } } } int main() { scanf("%d%d%d\n",&n,&m,&Mod); gets(s); insert(); for (int i=0;i<=9;++i) if (!ch[0][i]) ch[0][i]=++tot; make_fail(); f[0][0]=1; for (int i=1;i<=n;++i) for (int j=0;j<=tot;++j) { if (is_end[j]||is_end[fail[j]]) continue; for (int k=0;k<=9;++k) f[i][ch[j][k]]=(f[i][ch[j][k]]+f[i-1][j])%Mod; } for (int i=0;i<=tot;++i) printf("%d%c",f[1][i]," \n"[i==tot]); for (int i=0;i<=tot;++i) if (!is_end[i]) ans=(ans+f [i])%Mod; printf("%d\n",ans); }
矩阵优化
#include<iostream> #include<cstring> #include<cstdio> #include<queue> using namespace std; const int max_n=1005; const int max_m=105; int n,m,Mod,final,tot; char s[max_n]; int ch[max_m][20],fail[max_m];bool is_end[max_m]; struct hp{int a[max_m][max_m];}unit,A,f,ans; queue <int> q; inline void insert() { int now=0; for (int i=0;i<m;++i) { int x=s[i]-'0'; if (!ch[now][x]) ch[now][x]=++tot; now=ch[now][x]; } is_end[now]=true; } inline void make_fail() { while (!q.empty()) q.pop(); for (int i=0;i<=9;++i) if (ch[0][i]) q.push(ch[0][i]); while (!q.empty()) { int now=q.front(); q.pop(); for (int i=0;i<=9;++i) { if (!ch[now][i]) { ch[now][i]=ch[fail[now]][i]; continue; } int x=ch[now][i]; fail[x]=ch[fail[now]][i]; if (is_end[fail[x]]) is_end[x]=true; q.push(x); } } } inline hp cheng(hp a,hp b) { hp ans; memset(ans.a,0,sizeof(ans.a)); for (int i=0;i<=tot;++i) for (int j=0;j<=tot;++j) for (int k=0;k<=tot;++k) ans.a[i][j]=(ans.a[i][j]+a.a[i][k]*b.a[k][j]%Mod)%Mod; return ans; } inline hp matrix_fast_pow(hp a,int p) { hp ans=unit; for (;p;p>>=1,a=cheng(a,a)) if (p&1) ans=cheng(ans,a); return ans; } int main() { scanf("%d%d%d\n",&n,&m,&Mod); gets(s); insert(); for (int i=0;i<=9;++i) if (!ch[0][i]) ch[0][i]=++tot; make_fail(); for (int i=0;i<=tot;++i) if (!is_end[i]&&!is_end[fail[i]]) for (int k=0;k<=9;++k) A.a[i][ch[i][k]]=1; for (int i=0;i<=tot;++i) if (!is_end[i]&&!is_end[fail[i]]) for (int k=0;k<=9;++k) if (i==0) f.a[0][ch[i][k]]++; for (int i=0;i<=tot;++i) unit.a[i][i]=1; ans=matrix_fast_pow(A,n-1); ans=cheng(f,ans); for (int i=0;i<=tot;++i) if (!is_end[i]) final=(final+ans.a[0][i])%Mod; printf("%d\n",final); }
总结
之前写过的dp多复习复习吧,AC自动机好弱要多做做了。相关文章推荐
- linux 学习笔记(三):open、creat、close 函数的使用,文件的创建、打开与关闭
- AR
- .NET Core计划弃用project.json
- C#使用Redis集群缓存
- IIS负载均衡-Application Request Route详解第二篇:创建与配置Server Farm
- 想太多不如踏踏实实学习
- iOS UIVisualEffect 模糊动画的正确姿势
- 【BZOJ-4127】Abs 树链剖分 + 线段树 (有趣的姿势)
- 【我还不会的】
- 勾股定理每日一证 2
- 第107课: Spark Streaming电商广告点击综合案例底层数据层的建模和编码实现(基于MySQL)
- NLP相关
- [转] ReactNative Animated动画详解
- [转] Immutable 详解及 React 中实践
- bzoj4567: [Scoi2016]背单词
- 大型网站系统架构演化之路
- Stream常用操作min,reduce
- Android面试必考基础题
- 2016年5月16日--5月22日(每天1小时,共7小时,剩2977小时)
- Android NDK、cygwin安装及通过示例导出so库