zoukankan      html  css  js  c++  java
  • [BZOJ4502]串

    Description
    兔子们在玩字符串的游戏。首先,它们拿出了一个字符串集合S,然后它们定义一个字
    符串为“好”的,当且仅当它可以被分成非空的两段,其中每一段都是字符串集合S中某个字符串的前缀。
    比如对于字符串集合{"abc","bca"},字符串"abb","abab"是“好”的("abb"="ab"+"b",abab="ab"+"ab"),而字符串“bc”不是“好”的。
    兔子们想知道,一共有多少不同的“好”的字符串。

    Input
    第一行一个整数n,表示字符串集合中字符串的个数
    接下来每行一个字符串

    Output
    一个整数,表示有多少不同的“好”的字符串

    Sample Input
    2
    ab
    ac

    Sample Output
    9

    HINT
    1<=n<=10000,每个字符串非空且长度不超过30,均为小写字母组成。


    考虑总共组成的方案有前缀的平方种,然后考虑去重

    我们规定最右边的划分方案一定是合法的。考虑图中绿色的串,红色串显然为其后缀,又因为红绿串都是字符集的前缀,红串又是满足条件的最长的一个,这就是“最长前缀匹配后缀”,也就是AC自动机的fail指针,因此每当存在一个蓝串结尾的前缀时,红串就会给绿串一个-1的贡献

    于是问题就转化为:对于每一个串和它fail指针指向的串,求有多少个以两串相差部分为后缀的前缀。

    AC自动机上,根到每个节点的路径都对应一个前缀。而以一个串为后缀的串的个数,就是它fail树上子树大小减一(本身不算)。于是暴枚每个串即可。注意一个串的fail指针如果指向根,则不存在一个串是它的后缀,那它一定是所在答案串中最靠右的划分方式,就不应减去了。

    /*problem from Wolfycz*/
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define inf 0x7f7f7f7f
    using namespace std;
    typedef long long ll;
    typedef unsigned int ui;
    typedef unsigned long long ull;
    inline char gc(){
    	static char buf[1000000],*p1=buf,*p2=buf;
    	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int frd(){
    	int x=0,f=1; char ch=gc();
    	for (;ch<'0'||ch>'9';ch=gc())	if (ch=='-')	f=-1;
    	for (;ch>='0'&&ch<='9';ch=gc())	x=(x<<3)+(x<<1)+ch-'0';
    	return x*f;
    }
    inline int read(){
    	int x=0,f=1; char ch=getchar();
    	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')	f=-1;
    	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<3)+(x<<1)+ch-'0';
    	return x*f;
    }
    inline void print(int x){
    	if (x<0)	putchar('-');
    	if (x>9)	print(x/10);
    	putchar(x%10+'0');
    }
    const int N=1e4;
    struct S1{
    	int tot,root;
    	struct node{
    		int fa,fail,size,son[26];
    		node(){
    			fa=fail=size=0;
    			memset(son,0,sizeof(son));
    		}
    	}tree[N*30+10];
    	int h[N*30+10];
    	S1(){tot=root=0;}
    	void insert(char *s){
    		int len=strlen(s),p=root;
    		for (int i=0;i<len;i++){
    			if (!tree[p].son[s[i]-'a']){
    				tree[p].son[s[i]-'a']=++tot;
    				tree[tot].fa=p;
    			}
    			p=tree[p].son[s[i]-'a'];
    		}
    	}
    	void Get_Fail(){
    		int head=1,tail=0;
    		for (int i=0;i<26;i++){
    			if (tree[root].son[i]){
    				tree[tree[root].son[i]].fail=root;
    				h[++tail]=tree[root].son[i];
    			}
    		}
    		for (;head<=tail;head++){
    			int Now=h[head];
    			for (int i=0;i<26;i++){
    				if (tree[Now].son[i]){
    					tree[tree[Now].son[i]].fail=tree[tree[Now].fail].son[i];
    					h[++tail]=tree[Now].son[i];
    				}
    				else	tree[Now].son[i]=tree[tree[Now].fail].son[i];
    			}
    		}
    	}
    	void solve(){
    		for (int i=1;i<=tot;i++)
    			for (int j=tree[i].fail;j;j=tree[j].fail)
    				tree[j].size++;
    		ll Ans=1ll*tot*tot;
    		for (int i=1;i<=tot;i++){
    			int j=i,k=tree[i].fail;
    			if (!k)	continue;
    			while (k)	j=tree[j].fa,k=tree[k].fa;
    			Ans-=tree[j].size;
    		}
    		printf("%lld
    ",Ans);
    	}
    }AC;//Aho-Corasick automaton
    char s[40];
    int main(){
    	int n=read();
    	for (int i=1;i<=n;i++){
    		scanf("%s",s);
    		AC.insert(s);
    	}
    	AC.Get_Fail();
    	AC.solve();
    	return 0;
    }
    
  • 相关阅读:
    PHP学习之字符串
    PHP学习之常量
    PHP之数据类型
    AngularJS学习之Select(选择框)
    Angular JS 学习之Http
    PHP之echo/print
    Angular JS 学习之服务(Service)
    Angular JS 学习之过滤器
    git打包
    gdb分析core文件
  • 原文地址:https://www.cnblogs.com/Wolfycz/p/10040854.html
Copyright © 2011-2022 走看看