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++字符串的处理并不是很拿手,处理起来比较费劲,而且,算法题似乎很中意字符串的处理,有很多题目都涉及到它.字符串处理比较基础,但是很重要,因此,整理 ...
随机推荐
- 有关Fragment的知识点
关于判断Fragment是否可见,可以尝试参考使用Fragment中的两个方法: final boolean isHidden() Return true if the fragment has be ...
- C#中 Request, Request.params , Request.querystring , Request.Form 区别 与联系用法
C#中 Request, Request.params , Request.querystring , Request.Form 区别 与联系用法? Request.params , Request ...
- python——django的post请求
两次被同一块石头绊倒简直不可原谅!第一次写django程序的时候,就因为ajax post请求折腾了整整一天,时隔两个多月昨天又被虐一整晚.叔可忍婶儿也不能忍了!!!重要的事情写下来,为以后轻松碾压p ...
- css table-cell实现图文排列水平对齐
今天遇到一个样式:图文两列排列. 由于图片大小固定,于是就想到了用table-cell实现. <div class="container"> <div class ...
- redhat自定义安装必选
redhat自定义安装必选 1.桌面 ked桌面 x 窗口系统 2.应用程序 编辑器 基于文本的互联网 图形互联网 3.服务器 服务器配置工具 万维网服务器 Windows文件 FTP服务器
- 支付宝WAP支付接口开发(Node/Coffee语言)
此博客不更新很久了, 更新的文档在这, 有兴趣到这里围观: http://neutra.github.io/2013/%E6%94%AF%E4%BB%98%E5%AE%9DWAP%E6%94%AF%E ...
- Application.Run()和Form.Show()以及Form.ShowDialog()
ShowDialog()弹出模式化的窗体 Show()弹出非模式化的窗体 模式窗体,在关闭或隐藏前无法切换到主窗体. 非模式窗体,变换焦点使不必关闭窗体 总结:显示重要的信息,还是用模式窗体,如删除文 ...
- "Couldn't communicate with a helper application" in Xcode 7
解决方案 xcrun git config --global user.email you@yourdomain.com xcrun git config --global user.name &qu ...
- Java 和 Google Chrome 浏览器
来源:https://java.com/zh_CN/download/faq/chrome.xml 本文适用于: 浏览器: Chrome Java 版本: 7.0, 8.0 Chrome 不再支持 N ...
- Leetcode 详解(ReverseWords)
Leetcode里面关于字符串的一些问题,描述如下: Given an input string, reverse the string word by word. For example,Given ...