文章目錄
T1 於是他錯誤的點名開始了
#include<bits/stdc++.h>
using namespace std;
#define in Read()
inline int in{
int i=0,f=1;char ch;
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')ch=getchar(),f=-1;
while(isdigit(ch))i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
const int NNN=5e5+10;
int n;
int trie[NNN][26],sz;
char s[100];
int mark[NNN];
inline void update(){
int p=0,len=strlen(s+1);
for(int i=1;i<=len;++i){
int c=s[i]-'a';
if(!trie[p][c]) trie[p][c]=++sz;
p=trie[p][c];
}
++mark[p];
}
inline int query(){
int p=0,len=strlen(s+1);
for(int i=1;i<=len;++i){
int c=s[i]-'a';
if(!trie[p][c]) return 0;
p=trie[p][c];
}
++mark[p];
return mark[p]-1;
}
int main(){
n=in;
for(int i=1;i<=n;++i){
scanf("%s",s+1);
update();
}
n=in;
for(int i=1;i<=n;++i){
scanf("%s",s+1);
int val=query();
if(val==1)puts("OK");
if(val> 1)puts("REPEAT");
if(!val )puts("WRONG");
}
return 0;
}
T2 【模板】AC自動機(簡單版)
#include<bits/stdc++.h>
#define in Read()
using namespace std;
inline int in{
int i=0,f=1;char ch;
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')ch=getchar(),f=-1;
while(isdigit(ch))i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
const int NNN=1e6+10;
int n;
char s[NNN];
int trie[NNN][26],sz;
int val[NNN],fail[NNN],last[NNN];
inline void update(){
int p=0,len=strlen(s+1);
for(int i=1;i<=len;++i){
int c=s[i]-'a';
if(!trie[p][c]) trie[p][c]=++sz;
p=trie[p][c];
}
++val[p];
}
inline void get_fail(){
queue<int>q;
int p=0;
for(int i=0;i<26;++i){
p=trie[0][i];
if(!p)continue;
fail[p]=last[p]=0;
q.push(p);
}
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<26;++i){
p=trie[u][i];//j+1
if(!p){
trie[u][i]=trie[fail[u]][i];//連成一片
continue;
}
q.push(p);
int v=fail[u];//nxt[j+1]
while(v&&!trie[v][i]) v=fail[v];//while(j&&t[i+1](字符串間kmp就看存不存在)!=t[j+1]) j=nxt[j];
fail[p]=trie[v][i];//nxt[i]=j(++j)
last[p]=val[fail[p]]?fail[p]:last[fail[p]];//最大後綴
}
}
}
inline int query(){
int p=0,len=strlen(s+1);
int ans=0;
for(int i=1;i<=len;++i){
int c=s[i]-'a';
p=trie[p][c];
int tmp=0;
if(val[p])
tmp=p;
else if(last[p])
tmp=last[p];
while(tmp){
ans+=val[tmp];
val[tmp]=0;
tmp=last[tmp];
}
}
return ans;
}
int main(){
n=in;
for(int i=1;i<=n;++i){
scanf("%s",s+1);
update();
}
get_fail();
scanf("%s",s+1);
printf("%d",query());
return 0;
}
T3 【模板】AC自動機(加強版)
#include<bits/stdc++.h>
#define in Read()
#define int long long
using namespace std;
inline int in{
int i=0,f=1;char ch;
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')ch=getchar(),f=-1;
while(isdigit(ch))i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
int n;
const int NNN=1e6+10;
char s[200][100],t[NNN];
int sz;
struct ACAM{
int id,fail,last;
int son[26];
}ch[NNN];
struct Ans{
int id,cnt;
friend inline bool operator < (const Ans u,const Ans v){
if(u.cnt!=v.cnt) return u.cnt>v.cnt;
return u.id<v.id;
}
}ans[NNN];
inline void Clear(int x){
memset(ch[x].son,0,sizeof(ch[x].son));
ch[x].id=ch[x].fail=ch[x].last=0;
}
inline void update(int x){
int p=0,len=strlen(s[x]+1);
for(int i=1;i<=len;++i){
int c=s[x][i]-'a';
if(!ch[p].son[c]) ch[p].son[c]=++sz,Clear(sz);
p=ch[p].son[c];
}
ch[p].id=x;
}
inline void get_fail(){
queue<int>q;
int p=0;
for(int i=0;i<26;++i){
p=ch[0].son[i];
if(!p) continue;
q.push(p);
ch[p].last=ch[p].fail=0;
}
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<26;++i){
p=ch[u].son[i];
if(!p){
ch[u].son[i]=ch[ch[u].fail].son[i];
continue;
}
q.push(p);
int v=ch[u].fail;
while(v&&!ch[v].son[i]) v=ch[v].fail;
ch[p].fail=ch[v].son[i];
ch[p].last=ch[ch[p].fail].id?ch[p].fail:ch[ch[p].fail].last;
}
}
}
inline void query(){
int p=0,len=strlen(t+1);
for(int i=1;i<=len;++i){
int c=t[i]-'a';
p=ch[p].son[c];
int tmp=0;
if(ch[p].id) tmp=p;
else if(ch[p].last) tmp=ch[p].last;
while(tmp){
ans[ch[tmp].id].cnt+=1;
tmp=ch[tmp].last;
}
}
}
inline void work(){
for(int i=1;i<=n;++i){
scanf("%s",s[i]+1);
update(i);
ans[i].cnt=0;
ans[i].id=i;
}
get_fail();
scanf("%s",t+1);
query();
sort(ans+1,ans+n+1);
printf("%lld\n",ans[1].cnt);
if(ans[1].cnt){
printf("%s\n",s[ans[1].id]+1);
for(int i=2;i<=n;++i){
if(ans[i-1].cnt^ans[i].cnt) break;
printf("%s\n",s[ans[i].id]+1);
}
}
}
signed main(){
while(true){
n=in;
if(!n)break;
for(int i=1;i<=n;++i)ans[i].id=i;
sz=0;
Clear(0);
work();
}
return 0;
}
T4 【模板】AC自動機(二次加強版)
注意判重
- 法一:last數組優化
#include<bits/stdc++.h>
#define in Read()
#define int long long
using namespace std;
inline int in{
int i=0,f=1;char ch;
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')ch=getchar(),f=-1;
while(isdigit(ch))i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
const int NNN=5e5+10;
char t[NNN],s[NNN*10];
struct Trie{
int son[26];
int fail,last;
int id;
}ch[NNN];
int sz,ans[NNN],n;
int same[NNN];
inline void update(int x){
int p=0,len=strlen(t+1);
for(int i=1;i<=len;++i){
int c=t[i]-'a';
if(!ch[p].son[c]) ch[p].son[c]=++sz;
p=ch[p].son[c];
}
if(!ch[p].id) ch[p].id=x;
else same[x]=ch[p].id;
}
inline void get_fail(){
queue<int>q;
int p=0;
for(int i=0;i<26;++i){
p=ch[0].son[i];
if(!p) continue;
q.push(p);
}
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<26;++i){
p=ch[u].son[i];
if(!p){
ch[u].son[i]=ch[ch[u].fail].son[i];
continue;
}
q.push(p);
int v=ch[u].fail;
while(v&&!ch[v].son[i]) v=ch[v].fail;
ch[p].fail=ch[v].son[i];
ch[p].last=ch[ch[p].fail].id?ch[p].fail:ch[ch[p].fail].last;
}
}
}
inline void query(){
int p=0,len=strlen(s+1);
for(int i=1;i<=len;++i){
int c=s[i]-'a';
p=ch[p].son[c];
int tmp=0;
if(ch[p].id) tmp=p;
else if(ch[p].last) tmp=ch[p].last;
while(tmp){
++ans[ch[tmp].id];
tmp=ch[tmp].last;
}
}
}
signed main(){
n=in;
for(int i=1;i<=n;++i){
scanf("%s",t+1);
update(i);
}
get_fail();
scanf("%s",s+1);
query();
for(int i=1;i<=n;++i){
if(same[i]) printf("%lld\n",ans[same[i]]);
else printf("%d\n",ans[i]);
}
return 0;
}
- 法二:拓撲排序優化
跳樹:(每一個節點都要跳到葉子節點去)
拓撲排序後滑:(只跳入度的)
具體方法就是隻放入入度爲的點,統計之後扔掉,更新它們的入度
#include<bits/stdc++.h>
#define in Read()
using namespace std;
inline int in{
int i=0,f=1;char ch;
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')ch=getchar(),f=-1;
while(isdigit(ch))i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
const int NNN=2e5+10;
char t[NNN],s[NNN*10];
struct Trie{
int son[26];
int fail,into,ans,val;
}ch[NNN];
int sz,m[NNN],n;
//m:記錄單詞結束點的編號
inline void update(int x){
int p=0,len=strlen(t+1);
for(int i=1;i<=len;++i){
int c=t[i]-'a';
if(!ch[p].son[c]) ch[p].son[c]=++sz;
p=ch[p].son[c];
}
++ch[p].val;
m[x]=p;
}
inline void get_fail(){
queue<int>q;
int p=0;
for(int i=0;i<26;++i){
p=ch[0].son[i];
if(!p) continue;
q.push(p);
}
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<26;++i){
p=ch[u].son[i];
if(!p){
ch[u].son[i]=ch[ch[u].fail].son[i];
continue;
}
q.push(p);
int v=ch[u].fail;
while(v&&!ch[v].son[i]) v=ch[v].fail;
if(ch[v].son[i]!=p){
ch[p].fail=ch[v].son[i];
++ch[ch[v].son[i]].into;
}
}
}
}
inline void query(){
int p=0,len=strlen(s+1);
for(int i=1;i<=len;++i){
int c=s[i]-'a';
while(p&&!ch[p].son[c]) p=ch[p].fail;//一跳到底,後面的點只與最上面的點有關,可以根據它統計
p=ch[p].son[c];
if(!p)continue;//就是把tmp那很多步變成了一步
++ch[p].ans;
}
}
int main(){
n=in;
for(int i=1;i<=n;++i){
scanf("%s",t+1);
update(i);
}
get_fail();
scanf("%s",s+1);
query();
queue<int>q;
for(int i=1;i<=sz;++i)
if(!ch[i].into&&ch[i].fail)
q.push(i);
while(!q.empty()){
int u=q.front();q.pop();
ch[ch[u].fail].ans+=ch[u].ans;
--ch[ch[u].fail].into;
if(!ch[ch[u].fail].into)
q.push(ch[u].fail);
}
for(int i=1;i<=n;++i)
printf("%d\n",ch[m[i]].ans);
return 0;
}