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++字符串的处理并不是很拿手,处理起来比较费劲,而且,算法题似乎很中意字符串的处理,有很多题目都涉及到它.字符串处理比较基础,但是很重要,因此,整理 ...
随机推荐
- Markdown渲染后文章标题收缩控件
文章首发于szhshp的第三边境研究所(szhshp.org), 转载请注明 一个让Markdown-Post的标题拥有Collapse功能的JS 直接把鼠标放在这篇文章下方的header上,点击标题 ...
- Linux下漏洞提权
Linux下的漏洞提权 linux下一般都是系统漏洞提权,分为以下几个步骤:
- 【原创】基于SVM作短期时间序列的预测
[面试思路拓展] 对时间序列进行预测的方法有很多, 但如果只有几周的数据,而没有很多线性的趋势.各种实际的背景该如何去预测时间序列? 或许可以尝试下利用SVM去预测时间序列,那么如何提取预测的特征呢? ...
- archlinux 安装手记
Wiki常用软件 https://wiki.archlinux.org/index.php/Common_Applications -> 移动硬盘等的自动挂载 pacman -S gvfs-af ...
- php 使用curl模拟登录discuz以及模拟发帖
<?php$discuz_url = 'http://127.0.0.1/discuz/';//论坛地址$login_url = $discuz_url .'logging.php?action ...
- VHDL学习之模块调用
http://wenku.baidu.com/link?url=SsRPUVQAOKDR8yWfDhQlceCwfZQkI-KQMLFKTDGAh3KAPr2NwEgvj0d_EZjdnsB99Upp ...
- 我的毕业设计——基于安卓和.NET的笔记本电脑远程控制系统
手机端: 电脑端: 答辩完成后会开放代码.
- UITableViewCell 顶格
首先在ViewDidLoad 或者ViewWillAppear里边写 if ([_tabView respondsToSelector:@selector(setSeparatorInset:)]) ...
- SAX和DOM解析的区别
XML和JSon是ios解析文件的两种形式, 两种方法各有千秋. 1>. XML分为SAX和DOM两种方式 SAX是按顺序逐行读取文件, 查找到符合条件的内容时就会停止, 而DOM是讲内容一次性 ...
- [IOS 开发] 懒加载 (延迟加载) 的基本方式,好处,代码示例
懒加载的好处: 1> 不必将创建对象的代码全部写在viewDidLoad方法中,代码的可读性更强 2> 每个属性的getter方法中分别负责各自的实例化处理,代码彼此之间的独立性强,松耦合 ...