培训的时候忘讲了,字典树的第一维和标记数组,fail指针数组的大小都应该开成 模式串长*模式串数量
I. hdu1251 统计难题
这题唯一要注意的一点字典树的第一维要开到1e6,不过题目里不给范围也是挺毒的了
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+7;
struct trie{
int tr[maxn][26];
int exits[maxn];
int tot=0;
void insert(string str){
int len = str.length();
int p = 0;
for(int i=0;i<len;i++){
int c = str[i]-'a';
if(!tr[p][c])tr[p][c] = ++tot;
p = tr[p][c];
exits[p]++;
}
}
int query(string str){
int len = str.length();
int p = 0;
for(int i=0;i<len;i++){
int c = str[i] - 'a';
if(!tr[p][c])return 0;
p = tr[p][c];
}
return exits[p];
}
}t;
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
string str;
while(getline(cin,str)){
if(!str.length())break;
t.insert(str);
}
while(cin>>str){
cout<<t.query(str)<<endl;
}
}
J hdu1277 全文检索
这题如果按题目给的范围算的话应该是ac自动机的题,结果好像数据水了,map或者字典树暴力都能过。。好像也没什么要好讲的,看代码就明白了。
既然字典树暴力能过咱也放个字典树的吧,不过我的字典树暴力跑了900多ms,在超时的边缘疯狂试探。
字典树:
#include<bits/stdc++.h>
#define buff ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
const int maxn = 1e4*60+7;
vector<int> ans;
struct trie{
int tr[maxn][10];
int exits[maxn];
int tot = 0;
void insert(string str,int id){
int len = str.length();
int p = 0;
for(int i=0;i<len;i++){
int c = str[i]-'0';
if(!tr[p][c])tr[p][c] = ++tot;
p = tr[p][c];
}
exits[p]=id;
}
void query(string str){
int len = str.length();
int p = 0;
for(int i=0;i<len;i++){
int c = str[i]-'0';
if(!tr[p][c])return;
p = tr[p][c];
if(exits[p]){
ans.push_back(exits[p]);
exits[p]=0;
return ;
}
}
}
}Trie;
int main(){
buff;
int n,m;
cin>>n>>m;
string text;
string lin;
for(int i=0;i<n;i++){
cin>>lin;
text+=lin;
}
int id;
for(int i=0;i<m;i++){
cin>>lin>>lin>>lin;
id=0;
for(int i=0;lin[i]!=']';i++){
id*=10;id+=(lin[i]-'0');
}
cin>>lin;
Trie.insert(lin,id);
}
int len = text.length();
for(int i=0;i<len;i++){
string str = text.substr(i,len-i);
Trie.query(str);
}
if(ans.size()){
cout<<"Found key:";
for(auto i:ans){
cout<<" [Key No. "<<i<<"]";
}
}
else{
cout<<"No key can be found!";
}
cout<<endl;
}
ac自动机:
#include<bits/stdc++.h>
#define buff ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
const int maxn = 1e4*60+7;
vector<int> ans;
struct AC{
int trie[maxn][10];
int exits[maxn],fail[maxn];
int tot=0;
void insert(string s,int id){
int len = s.length();
int p = 0;
for(int i=0;i<len;i++){
int c = s[i]-'0';
if(!trie[p][c])trie[p][c] = ++tot;
p = trie[p][c];
}
exits[p] = id;
}
void build(){
queue<int> q;
for(int i=0;i<9;i++){
if(trie[0][i]){
fail[trie[0][i]] = 0;
q.push(trie[0][i]);
}
}
while(!q.empty()){
int p = q.front();
q.pop();
for(int i=0;i<10;i++){
if(trie[p][i]){
fail[trie[p][i]] = trie[fail[p]][i];
q.push(trie[p][i]);
}
else{
trie[p][i] = trie[fail[p]][i];
}
}
}
}
void query(string str){
int len = str.length();
int p = 0;
for(int i=0;i<len;i++){
int c = str[i]-'0';
p = trie[p][c];
for(int j=p;j&&exits[p];j=fail[j]){
ans.push_back(exits[p]);
exits[p]=0;
}
}
}
}ac;
int main(){
buff;
int n,m;
cin>>n>>m;
string text;
string lin;
for(int i=0;i<n;i++){
cin>>lin;
text+=lin;
}
int id;
for(int i=0;i<m;i++){
cin>>lin>>lin>>lin;
id=0;
for(int i=0;lin[i]!=']';i++){
id*=10;id+=(lin[i]-'0');
}
cin>>lin;
ac.insert(lin,id);
}
ac.build();
ac.query(text);
if(ans.size()){
cout<<"Found key:";
for(auto i:ans){
cout<<" [Key No. "<<i<<"]";
}
}
else{
cout<<"No key can be found!";
}
cout<<endl;
}
K. poj3764 The xor-longest Path
这题是蓝书上的例题,大家自己看蓝书即可
还有这题对时间复杂度和空间复杂度要求都挺高,需要减少不必要的初始化
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
#define buff ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int maxn = 1e5+7;
int tr[maxn*32][2];
int tot,ans;
void init1(){
tot=0;
ans=0;
tr[0][0]=0,tr[0][1]=0;
}
void insert(int x){
int p = 0;
for(int i=31;i>=0;i--){
bool c = x>>i&1;
if(!tr[p][c]){
tr[p][c] = ++tot;
tr[tot][0]=0;
tr[tot][1]=0;
}
p = tr[p][c];
}
}
void query(int x){
int p = 0;
int lin = 0;
for(int i=31;i>=0;i--){
bool c = x>>i&1;
if(tr[p][c^1]){
p = tr[p][c^1];
lin += pow(2,i);
}
else{
p = tr[p][c];
}
}
if(lin>ans)ans=lin;
}
int head[maxn*2],ver[maxn*2],edge[maxn*2],nex[maxn*2];
int vis[maxn];
int d[maxn];
int tot1=0;
void init(){
memset(head,0,sizeof head);
memset(vis,0,sizeof vis);
tot1=0;
}
void add(int x,int y,int z){
ver[++tot1]=y,edge[tot1]=z;
nex[tot1]=head[x],head[x]=tot1;
}
void dfs(int x){
vis[x]=1;
for(int i=head[x];i;i=nex[i]){
if(!vis[ver[i]]){
d[ver[i]] = d[x]^edge[i];
dfs(ver[i]);
}
}
}
int main(){
int n;
while(~scanf("%d",&n)){
init1();
init();
int x,y,z;
for(int i=1;i<n;i++){
scanf("%d%d%d",&x,&y,&z);
x++,y++;
add(x,y,z);
add(y,x,z);
}
dfs(1);
for(int i=1;i<=n;i++){
insert(d[i]);
query(d[i]);
}
printf("%d\n",ans);
}
}
hdu2222 Keywords Search
模板题
如果出现各种错误一般是空间没开好,没初始化或者别的细节
#include<bits/stdc++.h>
using namespace std;
const int N = (1e4+7)*50;
char str[N*2];
struct AC {
int tr[N][26],tot;
int end[N],fail[N]; //数组名叫end不太好反正
void insert(char *s){
int u=0;
int l=strlen(s);
for(int i=0;i<l;i++){
int c=s[i]-'a';
if(!tr[u][c])
tr[u][c]=++tot;
u=tr[u][c];
}
end[u]++;
}
void build(){
queue<int> q;
for(int i=0;i<26;i++){
if(tr[0][i]){
fail[tr[0][i]]=0;
q.push(tr[0][i]);
}
}
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=0;i<26;i++){
if(tr[u][i]){
fail[tr[u][i]]=tr[fail[u]][i];
q.push(tr[u][i]);
}
else{
tr[u][i]=tr[fail[u]][i];
}
}
}
}
int query(char *t){
int l=strlen(t);
int pos=0,res=0;
for(int i=0;i<l;i++){
int c=t[i]-'a';
pos=tr[pos][c];
for(int j=pos;j&&end[j]!=-1;j=fail[j]){
res+=end[j];
end[j]=-1;
}
}
return res;
}
void init(){
tot=0;
memset(end,0,sizeof(end));
memset(tr,0,sizeof(tr));
}
}ac;
int main(){
int t;
scanf("%d",&t);
while(t--){
ac.init();
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%s",str),ac.insert(str);
ac.build();
scanf("%s",str);
printf("%d\n",ac.query(str));
}
return 0;
}
M hdu2896 病毒侵袭
这题有点卡空间,不能乱用memset
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+7;
int sum=0;
struct AC{
int trie[maxn][130];
int exits[maxn],fail[maxn];
int tot=0;
void insert(string s,int id){
int len = s.length();
int p = 0;
for(int i=0;i<len;i++){
int c = s[i];
if(!trie[p][c])trie[p][c]=++tot;
p = trie[p][c];
}
exits[p]=id;
}
void build(){
queue<int> q;
for(int i=0;i<128;i++){
if(trie[0][i]){
fail[trie[0][i]]=0;
q.push(trie[0][i]);
}
}
while(!q.empty()){
int p = q.front();
q.pop();
for(int i=0;i<128;i++){
if(trie[p][i]){
fail[trie[p][i]] = trie[fail[p]][i];
q.push(trie[p][i]);
}
else{
trie[p][i] = trie[fail[p]][i];
}
}
}
}
void query(string str,int id){
vector<int> ans;
ans.clear();
int len = str.length();
int p = 0;
for(int i=0;i<len;i++){
int c = str[i];
p = trie[p][c];
for(int j=p;j&&exits[j];j=fail[j]){
ans.push_back(exits[j]);
}
}
sort(ans.begin(),ans.end());
if(ans.size()){
sum++;
cout<<"web "<<id<<":";
for(auto i:ans){
cout<<" "<<i;
}
cout<<endl;
}
}
}ac;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n,m;
cin>>n;
string lin;
for(int i=1;i<=n;i++){
cin>>lin;
ac.insert(lin,i);
}
ac.build();
cin>>m;
for(int i=1;i<=m;i++){
cin>>lin;
ac.query(lin,i);
}
cout<<"total: "<<sum<<endl;
}
N POJ 2778 DNA Sequence
这题的精髓在于利用矩阵进行计数,感觉以我的水平搞的不是很清楚,给大家一些很牛逼的资源吧:
-
去年学长给我们讲解AC自动机时的课件,清晰准确,对本题还特别做了讲解,强烈推荐!
-
kuangbin大佬的题解
-
csdn上某大佬的博客