AC自动机裸题
HDU 2222 Keywords Search
模板题。对模式串建立AC自动机然后在trie树上找一遍目标串即可。
# include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <set> # include <cmath> # include <algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi 3.1415926535 # define eps 1e-4 # define MOD 1000000007 # define INF 1000000000 # define mem(a,b) memset(a,b,sizeof(a)) # define FOR(i,a,n) for(int i=a; i<=n; ++i) # define FO(i,a,n) for(int i=a; i<n; ++i) # define bug puts("H"); # define lch p<<1,l,mid # define rch p<<1|1,mid+1,r # define mp make_pair # define pb push_back typedef pair<int,int> PII; typedef vector<int> VI; # pragma comment(linker, "/STACK:1024000000,1024000000") typedef long long LL; inline int Scan() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void Out(int a) { if(a<0) {putchar('-'); a=-a;} if(a>=10) Out(a/10); putchar(a%10+'0'); } const int N=500010; //Code begin... int trie[N][27], top, fail[N]; void init(){top=1; mem(trie[0],0);} void ins(char *s){ int rt, nxt; for (rt=0; *s; rt=nxt, ++s){ nxt=trie[rt][*s-97]; if (!nxt) mem(trie[top],0), trie[rt][*s-97]=nxt=top++; } ++trie[rt][26]; } void makefail(){ int u, v, bg, ed; static int q[N]; fail[0]=bg=ed=0; FO(i,0,26) if ((v=trie[0][i])) fail[q[ed++]=v]=0; while (bg<ed){ u=q[bg++]; FO(i,0,26) { if ((v=trie[u][i])) fail[q[ed++]=v]=trie[fail[u]][i]; else trie[u][i]=trie[fail[u]][i]; } } } int ac(char *s){ static bool vis[N]; int ans=0; mem(vis,0); for (int i=0; *s; ++s) { i=trie[i][*s-97]; for (int j=i; j&&!vis[j]; j=fail[j]) vis[j]=1, ans+=trie[j][26]; } return ans; } char str[1000005]; int main () { int T, n; scanf("%d",&T); while (T--) { scanf("%d",&n); init(); while (n--) scanf("%s",str), ins(str); scanf("%s",str); makefail(); printf("%d\n",ac(str)); } return 0; }
HDU 2896 病毒侵袭
把AC自动机的节点维护的东西改一改就行了。不过由于目标串很多,每次都fillchar一遍vis数组会超时。使用以前学的黑科技按时间戳更新vis即可AC。
# include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <set> # include <cmath> # include <algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi 3.1415926535 # define eps 1e-4 # define MOD 1000000007 # define INF 1000000000 # define mem(a,b) memset(a,b,sizeof(a)) # define FOR(i,a,n) for(int i=a; i<=n; ++i) # define FO(i,a,n) for(int i=a; i<n; ++i) # define bug puts("H"); # define lch p<<1,l,mid # define rch p<<1|1,mid+1,r # define mp make_pair # define pb push_back typedef pair<int,int> PII; typedef vector<int> VI; # pragma comment(linker, "/STACK:1024000000,1024000000") typedef long long LL; inline int Scan() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void Out(int a) { if(a<0) {putchar('-'); a=-a;} if(a>=10) Out(a/10); putchar(a%10+'0'); } const int N=150010; //Code begin... int trie[N][98], top, fail[N], ans[4], q[N]; bool vis[N]; queue<int>Q; void init(){top=1; mem(trie[0],0);} void ins(char *s, int id){ int rt, nxt; for (rt=0; *s; rt=nxt, ++s){ nxt=trie[rt][*s-32]; if (!nxt) mem(trie[top],0), trie[rt][*s-32]=nxt=top++; } trie[rt][95]=id; } void makefail(){ int u, v, bg, ed; fail[0]=bg=ed=0; FO(i,0,95) if ((v=trie[0][i])) fail[q[ed++]=v]=0; while (bg<ed){ u=q[bg++]; FO(i,0,95) { if ((v=trie[u][i])) fail[q[ed++]=v]=trie[fail[u]][i]; else trie[u][i]=trie[fail[u]][i]; } } } void ac(char *s){ int v; while (!Q.empty()) v=Q.front(), Q.pop(), vis[v]=0; for (int i=0; *s; ++s) { i=trie[i][*s-32]; for (int j=i; j&&!vis[j]; j=fail[j]) { vis[j]=1; Q.push(j); if (trie[j][95]) ans[++ans[0]]=trie[j][95]; } } } char str[10005]; int main () { int n, m, total=0; scanf("%d",&n); init(); getchar(); FOR(i,1,n) gets(str), ins(str,i); makefail(); scanf("%d",&m); getchar(); FOR(i,1,m) { gets(str); ans[0]=0; ac(str); if (ans[0]) ++total; else continue; printf("web %d:",i); sort(ans+1,ans+ans[0]+1); FOR(j,1,ans[0]) printf(" %d",ans[j]); putchar('\n'); } printf("total: %d\n",total); return 0; }
HDU 3065 病毒侵袭持续中
统计每个模式串的出现次数,不用vis数组就行了。这题由于模式串的特殊性,只需要建立26叉树即可。
# include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <set> # include <cmath> # include <algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi 3.1415926535 # define eps 1e-4 # define MOD 1000000007 # define INF 1000000000 # define mem(a,b) memset(a,b,sizeof(a)) # define FOR(i,a,n) for(int i=a; i<=n; ++i) # define FO(i,a,n) for(int i=a; i<n; ++i) # define bug puts("H"); # define lch p<<1,l,mid # define rch p<<1|1,mid+1,r # define mp make_pair # define pb push_back typedef pair<int,int> PII; typedef vector<int> VI; # pragma comment(linker, "/STACK:1024000000,1024000000") typedef long long LL; inline int Scan() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void Out(int a) { if(a<0) {putchar('-'); a=-a;} if(a>=10) Out(a/10); putchar(a%10+'0'); } const int N=50010; //Code begin... int trie[N][27], top, fail[N], num[1005]; char ss[1005][55]; void init(){top=1; mem(trie[0],0);} void ins(char *s, int id){ int rt, nxt; for (rt=0; *s; rt=nxt, ++s){ nxt=trie[rt][*s-'A']; if (!nxt) mem(trie[top],0), trie[rt][*s-'A']=nxt=top++; } trie[rt][26]=id; } void makefail(){ int u, v, bg, ed; static int q[N]; fail[0]=bg=ed=0; FO(i,0,26) if ((v=trie[0][i])) fail[q[ed++]=v]=0; while (bg<ed){ u=q[bg++]; FO(i,0,26) { if ((v=trie[u][i])) fail[q[ed++]=v]=trie[fail[u]][i]; else trie[u][i]=trie[fail[u]][i]; } } } void ac(char *s){ int v; for (int i=0; *s; ++s) { if (*s<'A'||*s>'Z') {i=0; continue;} i=trie[i][*s-'A']; for (int j=i; j; j=fail[j]) if ((v=trie[j][26])) ++num[v]; } } char str[2000005]; int main () { int n; while (~scanf("%d",&n)) { init(); mem(num,0); getchar(); FOR(i,1,n) gets(ss[i]), ins(ss[i],i); makefail(); gets(str); ac(str); FOR(i,1,n) { if (!num[i]) continue; printf("%s: %d\n",ss[i],num[i]); } } return 0; }