ACM 字符串 题目整理
AC自动机
UVa 11468 Substring
AC自动机+概率DP。
注意要补全不存在的边。
为什么要补全不存在的边呢?补全以后可以直接找到状态的转移,即从所有子节点就可以实现所有状态转移。
#include<iostream> #include<vector> #include<cmath> #include<map> #include<algorithm> #include<cstring> #include<cstdio> #include<cstdlib> #include<queue> #include<string> #define INF 1000000000LL #define ll long long #define maxnode 4000+5 #define sigma_size 62 using namespace std; struct Tire { ],end[maxnode],fail[maxnode]; int root,L; int newnode() { memset(ch[L],,sizeof(ch[L])); end[L++]=; ; } void init() { L=; fail[]=; end[]=; root=newnode(); } int idx(char c) { if('a'<=c&&c<='z') return c-'a'; ; ; } void insert(char* word) { ; ; word[i]; ++i) { int x=idx(word[i]); if(!ch[now][x]) ch[now][x]=newnode(); now=ch[now][x]; } end[now]=; } void build() { queue<int> que; ; i<sigma_size; ++i) { ][i]) { que.push(ch[][i]); fail[ch[][i]]=; } } while(!que.empty()) { int q=que.front(); que.pop(); ; i<sigma_size; ++i) { int u=ch[q][i]; if(!u) { ch[q][i]=ch[fail[q]][i]; continue; } int v=fail[q]; que.push(u); while(v&&!ch[v][i]) v=fail[v]; fail[u]=ch[v][i]; end[u]|=end[fail[u]]; } } } }; Tire ac; ]; ][]; ][]; ]; double dp(int now,int L) { if(!L) return 1.0; if(vis[now][L]) return f[now][L]; vis[now][L]=true; f[now][L]=0.0; ; i<sigma_size; ++i) if(cha[i]) { int u=ac.ch[now][i]; if(!ac.end[u]) f[now][L]+=pro[i]*dp(u,L-); } return f[now][L]; } int main() { ; //freopen("read.txt","r",stdin); //freopen("out.txt","w",stdout); scanf("%d",&T); while(T--) { int k; scanf("%d",&k); ac.init(); memset(vis,,sizeof(vis)); memset(cha,,sizeof(cha)); ; i<k; ++i) { ]; scanf("%s",word); ac.insert(word); } ac.build(); int n; scanf("%d",&n); memset(pro,,sizeof(pro)); ; i<n; ++i) { ]; double p; scanf("%s%lf",word,&p); ]); cha[q]=true; pro[q]=p; } int L; scanf("%d",&L); ,L); printf("Case #%d: %.6lf\n",++kase,ans); } ; }
HDU 2825 Wireless Password
AC自动机+状态压缩DP
求长度为n的字符串中包含超过k个模式串的个数。
dp[i][j][k]表示长为i,当前状态为j时的字符串包括k个串时的个数,k为集合。
状态压缩使每个串唯一,而不必考虑重复。串可以重叠而考虑AC自动机。
另外注意如果当前dp为0,那就不用刷表了。
#include<iostream> #include<vector> #include<cmath> #include<map> #include<algorithm> #include<cstring> #include<cstdio> #include<cstdlib> #include<queue> #include<string> #define ll long long #define maxnode 105 #define sigma_size 26 #define maxn 100 #define MOD 20090717 using namespace std; int n,m,K; int countBit(int val) { ; while(val) { cnt+=val%; val/=; } return cnt; } struct Tire { int ch[maxnode][sigma_size],end[maxnode],fail[maxnode]; int root,L; int newnode() { memset(ch[L],,sizeof(ch[L])); end[L++]=; ; } void init() { L=; fail[]=; end[]=; root=newnode(); } int idx(char c) { return c-'a'; } void insert(char* word,int p) { ; ; word[i]; ++i) { int x=idx(word[i]); if(!ch[now][x]) ch[now][x]=newnode(); now=ch[now][x]; } end[now]=<<p; } void build() { queue<int> que; ; i<sigma_size; ++i) { ][i]) { que.push(ch[][i]); fail[ch[][i]]=; } } while(!que.empty()) { int q=que.front(); que.pop(); ; i<sigma_size; ++i) { int u=ch[q][i]; if(!u) { ch[q][i]=ch[fail[q]][i]; continue; } int v=fail[q]; que.push(u); while(v&&!ch[v][i]) v=fail[v]; fail[u]=ch[v][i]; end[u]|=end[fail[u]]; } } } ][maxn][(<<)+]; int solve() { memset(dp,,sizeof(dp)); dp[][][]=; ; i<n; ++i) { ; j<L; ++j) { ; k<(<<m); ++k) if(dp[i][j][k]) { ; l<; ++l) { int u=ch[j][l]; ][u][k|end[u]]; res+=dp[i][j][k]; res%=MOD; } } } } ; ; j<(<<m); ++j) if(countBit(j)>=K) { ; i<L; ++i) { ans+=dp[n][i][j]; ans%=MOD; } } return ans; } }; Tire ac; int main() { while(scanf("%d%d%d",&n,&m,&K)!=EOF) { if(!n&&!m&&!K) break; ac.init(); ; i<m; ++i) { ]; scanf("%s",word); ac.insert(word,i); } ac.build(); printf("%d\n",ac.solve()); } ; }
POJ 3691 DNA repair
AC自动机+DP
问修改最少字符使得串中不含模式子串。
dp[i][j]表示当前是当串中第j个位置是第i个节点状态时的最优解。
当c不是结束节点的时候,c表示从i转移到的状态
dp[i][j]=min{dp[c][j+1]+1}//如果此时需要修改
dp[i][j]=min{dp[c][j+1]}//如果此时不修改
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <vector> #include <queue> #define ll long long using namespace std; ; ; ; struct Tire { int ch[maxnode][sigma_size]; int end[maxnode],fail[maxnode]; int sz; int newnode() { memset(ch[sz],,sizeof(ch[sz])); fail[sz]=; end[sz++]=; ; } void init() { sz=; newnode(); } int idx(char c) { ; ; ; ; } void insert(char *word) { ; ; word[i]; ++i) { int x=idx(word[i]); if(!ch[now][x]) ch[now][x]=newnode(); now=ch[now][x]; } end[now]=; } void build() { queue<int> que; ; i<sigma_size; ++i) { ][i]; if(u) { fail[u]=; que.push(u); } } while(!que.empty()) { int q=que.front(); que.pop(); ; i<sigma_size; ++i) { int u=ch[q][i],v=fail[q]; if(!u) { ch[q][i]=ch[v][i]; continue; } que.push(u); while(v&&!ch[v][i]) v=fail[v]; fail[u]=ch[v][i]; end[u]|=end[fail[u]]; } } } }; ][]; ][]; ]; int N; Tire ac; int dp(int now,int L) { ; if(vis[now][L]) return f[now][L]; vis[now][L]=true; f[now][L]=inf; ; i<; ++i) { int y=ac.idx(str[L]); int u=ac.ch[now][i]; if(!ac.end[u]) { )!=inf) f[now][L]=min(f[now][L],dp(u,L+)+); )!=inf) f[now][L]=min(f[now][L],dp(u,L+)); } } return f[now][L]; } int main() { ; while(scanf("%d",&n)&&n) { ]; ac.init(); memset(vis,,sizeof(vis)); ; i<=n; ++i) { scanf("%s",word); ac.insert(word); } scanf("%s",str); ac.build(); N=strlen(str); printf("Case %d: ",++kase); ,); if(ans==inf) puts("-1"); else printf("%d\n",ans); } ; }
字典树
POJ 3630 Phone List
问有没有一个电话号是另一个电话号的前缀。
典型的trie树,时间复杂度是10n。注意不要边读入边判断。否则像12、2这样就判不出来。
#include<cstdio> #include<vector> #include<algorithm> #include<queue> #include<cstring> #define LL unsigned int using namespace std; ; ; struct Tire { int ch[maxnode][sigma_size]; int end[maxnode]; int sz; int newnode() { memset(ch[sz],,sizeof(ch[sz])); end[sz]=; return sz++; } void init() { sz=; newnode(); } bool insert(char *word,int v) { ; ; word[i]; ++i) { '; if(!ch[now][x]) ch[now][x]=newnode(); now=ch[now][x]; if(end[now]&&end[now]!=v) return false; } end[now]=v; return true; } }; Tire tree; ][]; int main() { int T; scanf("%d",&T); while(T--) { int n; scanf("%d",&n); bool ok=true; tree.init(); ; i<=n; ++i) { scanf("%s",numb[i]); if(ok&&!tree.insert(numb[i],i)) ok=false; } ; i<=n&&ok; ++i) { if(!tree.insert(numb[i],i)) ok=false; } if(ok) puts("YES"); else puts("NO"); } ; }
POJ 1204 Word Puzzles
在一个字符矩阵中寻找出现的字符串,并输出头字符的位置和方向。
可以用字典树来做。枚举每个位置再枚举方向,这样每次遍历一个字符串看是否出现了模式串。
#include<cstdio> #include<vector> #include<algorithm> #include<queue> #include<cstring> #define LL unsigned int using namespace std; *+; ; ][]; int C,L,W; bool judge(int x,int y) { <=x&&x<L&&<=y&&y<C; } int ax,ay,d; ][]; ][]= {{-,},{-,},{,},{,},{,},{,-},{,-},{-,-}}; struct Tire { int ch[maxnode][sigma_size]; int end[maxnode]; int sz; int newnode() { memset(ch[sz],-,sizeof(ch[sz])); end[sz]=; return sz++; } void init() { sz=; newnode(); } int idx(char c) { return c-'A'; } void insert(char *word,int v) { ; ; word[i]; ++i) { int x=idx(word[i]); ) ch[now][x]=newnode(); now=ch[now][x]; } end[now]=v; } void find(int x,int y) { ; ) { int c=idx(mat[x][y]); now=ch[now][c]; ) break; if(end[now]) { ans[end[now]][]=ax; ans[end[now]][]=ay; ans[end[now]][]=d; end[now]=; } x+=dir[d][]; y+=dir[d][]; if(!judge(x,y)) break; } } void find(int x,int y,int now) { )return; ) { ans[end[now]][]=ax; ans[end[now]][]=ay; ans[end[now]][]=d; end[now]=; } if(!judge(x,y)) return; find(x+dir[d][],y+dir[d][],ch[now][idx(mat[x][y])]); } }; Tire tree; int main() { while(scanf("%d%d%d",&L,&C,&W)!=EOF) { ; i<L; ++i) scanf("%s",mat[i]); tree.init(); ; i<=W; ++i) { ]; scanf("%s",str); tree.insert(str,i); } ; i<L; ++i) ; j<C; ++j) ; k<; ++k) { ax=i; ay=j; d=k; tree.find(i,j); } ; i<=W; ++i) printf(],ans[i][],ans[i][]+'A'); } ; }
ACM 字符串 题目整理的更多相关文章
- ACM 矩阵题目整理
先从最基础的矩阵快速幂加速递推开始. HDU 1005 Number Sequence |f[n-2],f[n-1]|* |0 B| =|f[n-1], B*f[n-2]+A*f[n-1]|=|f[n ...
- 【好好补题,因为没准题目还会再出第三遍!!】ACM字符串-组合数学(官方题解是数位DP来写)
ACM字符串 .长度不能超过n .字符串中仅包含大写字母 .生成的字符串必须包含字符串“ACM”,ACM字符串要求连在一块! ok,是不是很简单?现在告诉你n的值,你来告诉我这样的字符串有多少个 输入 ...
- Noip往年题目整理
Noip往年题目整理 张炳琪 一.历年题目 按时间倒序排序 年份 T1知识点 T2知识点 T3知识点 得分 总体 2016day1 模拟 Lca,树上差分 期望dp 144 挺难的一套题目,偏思维难度 ...
- NOIp初赛题目整理
NOIp初赛题目整理 这个 blog 用来整理扶苏准备第一轮 csp 时所做的与 csp 没 有 关 系 的历年 noip-J/S 初赛题目,记录了一些我从不知道的细碎知识点,还有一些憨憨题目,不定期 ...
- ACM - 动态规划专题 题目整理
CodeForces 429B Working out 预处理出从四个顶点到某个位置的最大权值,再枚举相遇点,相遇的时候只有两种情况,取最优解即可. #include<iostream> ...
- ACM 暴力搜索题 题目整理
UVa 129 Krypton Factor 注意输出格式,比较坑爹. 每次要进行处理去掉容易的串,统计困难串的个数. #include<iostream> #include<vec ...
- ACM金牌选手整理的【LeetCode刷题顺序】
算法和数据结构知识点图 首先,了解算法和数据结构有哪些知识点,在后面的学习中有 大局观,对学习和刷题十分有帮助. 下面是我花了一天时间花的算法和数据结构的知识结构,大家可以看看. 后面是为大家 精心挑 ...
- BZOJ 题目整理
bzoj 500题纪念 总结一发题目吧,挑几道题整理一下,(方便拖板子) 1039:每条线段与前一条线段之间的长度的比例和夹角不会因平移.旋转.放缩而改变,所以将每条轨迹改为比例和夹角的序列,复制一份 ...
- C和C++字符串处理整理
在刷leetcode题目的过程中,发现自己对于c和c++字符串的处理并不是很拿手,处理起来比较费劲,而且,算法题似乎很中意字符串的处理,有很多题目都涉及到它.字符串处理比较基础,但是很重要,因此,整理 ...
随机推荐
- hibernate hql
hibernate在使用hql进行select count(*) from ObjectA left join fetch apath 时会报错,多余的left join去掉即可.
- loadrunner json
Action(){ web_custom_request("JRPT_WriteLog", //VuGen中树形视图中显示的名称 "Url=url", //请求 ...
- html标签
HTML常用标签 首先要知道html标签的一些特点: 1.类似“<关键字>”这样由尖括号包关键字组成,例如<html>,<div>…… 2.一般是成对出现的,由开始 ...
- 十天精通CSS3学习笔记 part3
第8章 CSS3中的变形与动画(上) 变形--旋转 rotate() 旋转rotate()函数通过指定的角度参数使元素相对原点进行旋转.它主要在二维空间内进行操作,设置一个角度值,用来指定旋转的幅度. ...
- 十天精通CSS3学习笔记 part1
http://www.imooc.com/learn/33 第1章 初识CSS3 什么是CSS3? CSS3是CSS2的升级版本,3只是版本号,它在CSS2.1的基础上增加了很多强大的新功能. 目前主 ...
- Python学习笔记之抽象
一.创建函数 >>> import math >>> x=1 >>> y=math.sqrt >>> callable(x) # ...
- Github windows客户端简单使用教程
1. 首先到官网下载Github客户端,官网地址:https://desktop.github.com/ 2. 点击上图红框的按钮开始下载客户端. 3. 双击下载好的客户端,开始安装. 双击之后出现一 ...
- 《精通C#》第十二章 Linq
Linq是在.Net3.5之后首次引入的,这种查询语言简单易学,可用范围非常广泛在学着之前,一直用在数据库操作之上,但是在学习这节课之后才发现,凡是实现泛型的接口类型都可以使用linq,简单来说就是实 ...
- WebForm复杂控件
Calendar 日历: FileUpdate 文件上传: Image 图片,可以直接给URL: Repeater: HeaderTemplate - 在加载开始执行一遍 ItemTemplate ...
- tfs中如何创建团队项目及如何操作团队项目
创建团队项目集合 tfs server管理控制台\团队项目集合页面.选择'创建集合'链接,按向导即可创建项目集合. 创建团队项目 创建好团队项目集合后,就要开始创建团队项目了. 进入vs,连接上tfs ...