zoukankan      html  css  js  c++  java
  • bzoj2434: [Noi2011]阿狸的打字机

    传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2434

    一个讲得很详细的题解:http://blog.csdn.net/huzecong/article/details/7769988

    思路:这题的想法有点神啊....

    先构建AC自动机,然后怎么判断一个串b是a的子串呢?用fail指针就可以了。如果a串中有节点可以通过fail指针走到b的终止节点,那么b就在a中出现过。有n个节点可以走到b,那么b就出现过n次。

    现在就有一个暴力的想法,枚举a串的每个节点的fail看是否能到b,但是这是显然会T的。

    然后我们可以倒过来想,把fail指针反向,建一棵fail树,对于b串,统计子树中有多少个a串的节点即可。

    子树的节点的dfs序是相连的。

    这样我们就可以用树状数组维护一下就好了。

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    const int maxn=100010;
    using namespace std;
    int m,len,num,preq[maxn],nowq[maxn],sonq[maxn],l[maxn],r[maxn],bit[maxn],pos[maxn],cnt,pre[maxn],now[maxn],son[maxn],ans[maxn];char s[maxn],ch;
    void change(int x,int val){for (;x<=cnt;x+=x&-x) bit[x]+=val;}
    int query(int x){
    	int res=0;
    	for (;x;x-=x&-x) res+=bit[x];
    	return res;
    }
    void add(int a,int b){pre[++num]=now[a],now[a]=num,son[num]=b;}
    void read(int &x){
    	for (ch=getchar();!isdigit(ch);ch=getchar());
    	for (x=0;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    }
    
    struct AC_DFA{
    	int tot,ch[maxn][26],fail[maxn],q[maxn],fa[maxn],head,tail;
    	void build(){
    		int p=0,id=0;
    		for (int i=0;i<len;i++)
    			if (s[i]=='P') pos[++id]=p;
    			else if (s[i]=='B') p=fa[p];
    			else{
    				if (!ch[p][s[i]-'a']) ch[p][s[i]-'a']=++tot,fa[tot]=p;
    				p=ch[p][s[i]-'a'];
    			}
    	}
    	void getfail(){
    		head=0,q[tail=1]=0,fail[0]=-1;
    		while (head!=tail){
    			int x=q[++head];
    			for (int i=0;i<26;i++)
    				if (ch[x][i])
    					q[++tail]=ch[x][i],fail[ch[x][i]]=x==0?0:ch[fail[x]][i];
    				else ch[x][i]=x==0?0:ch[fail[x]][i];
    		}
    	}
    	void dfs(int x){
    		l[x]=++cnt;
    		for (int y=now[x];y;y=pre[y])
    			dfs(son[y]);
    		r[x]=cnt;
    	}
    	void work(){
    		int p=0,id=0;
    		change(l[0],1);
    		for (int i=0;i<len;i++)
    			if (s[i]=='P'){
    				id++;
    				for (int y=nowq[id];y;y=preq[y]){
    					int t=pos[sonq[y]];
    					ans[y]=query(r[t])-query(l[t]-1);
    				}
    			}
    			else if (s[i]=='B') change(l[p],-1),p=fa[p];
    			else p=ch[p][s[i]-'a'],change(l[p],1);
    	}
    }T;
    
    int main(){
    	scanf("%s%d",s,&m);len=strlen(s);
    	for (int i=1,x,y;i<=m;i++){
    		read(x),read(y);
    		preq[i]=nowq[y],sonq[i]=x,nowq[y]=i;
    	}
    	T.build(),T.getfail();
    	for (int i=1;i<=T.tot;i++) add(T.fail[i],i);
    	T.dfs(0),T.work();
    	for (int i=1;i<=m;i++) printf("%d
    ",ans[i]);
    	return 0;
    }


  • 相关阅读:
    毕业季 | 如何做出99分的答辩PPT
    git: error setting certificate verify locations解决办法
    获取表格里面的内容
    MD5加密算法
    mybatis多条件批量删除
    layer.confirm
    DevExpress控件的GridControl实现行多选
    sz与rz命令
    @TableField的使用
    C# WinForm 中Label自动换行 解决方法
  • 原文地址:https://www.cnblogs.com/thythy/p/5493563.html
Copyright © 2011-2022 走看看