后缀自动机1003 HDU 4416
2016-08-08 09:55
393 查看
题意:
给一个模式串,然后给n个匹配串,问模式串里有多少个子串是n个匹配串里都不存在的
思路:
就是注意一个性质就行了
假设当前节点的len==6,当前节点的pre节点len==2
这个节点接收的状态就是以当前节点为最后一个字符的后缀的长度是3~6里
比如当前节点的最长后缀是abcabb(sam.len==6),pre节点是b(sam.len==2)
那么当前节点的接收子串是abcabb,bcabb,cabb,abb
pre节点接收的状态就是bb,b
所以当前节点的状态包含pre节点
就是这个性质…
然后就比较简单了
给一个模式串,然后给n个匹配串,问模式串里有多少个子串是n个匹配串里都不存在的
思路:
就是注意一个性质就行了
假设当前节点的len==6,当前节点的pre节点len==2
这个节点接收的状态就是以当前节点为最后一个字符的后缀的长度是3~6里
比如当前节点的最长后缀是abcabb(sam.len==6),pre节点是b(sam.len==2)
那么当前节点的接收子串是abcabb,bcabb,cabb,abb
pre节点接收的状态就是bb,b
所以当前节点的状态包含pre节点
就是这个性质…
然后就比较简单了
#include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> #include<math.h> #include<queue> #include<stack> #include<string> #include<vector> #include<map> #include<set> using namespace std; #define lowbit(x) (x&(-x)) typedef long long LL; const int maxn = 300005; const int inf=(1<<28)-1; struct sam_node { int fa,son[26]; int len; void init(int _len) { len=_len;fa=-1; memset(son,-1,sizeof(son)); } }; class SAM { public: int root,last,tots; sam_node sam[maxn*2];//length*2 int dp[maxn*2]; SAM() { init(); } void init() { tots=0; root=last=0; sam[tots].init(0); } void extend(char ch) { int w=ch-'a'; int p=last; int np=++tots;sam[tots].init(sam[p].len+1); int q,nq;while(p!=-1&&sam[p].son[w]==-1) sam[p].son[w]=np,p=sam[p].fa; if (p==-1) sam[np].fa=root; else { q=sam[p].son[w]; if (sam[p].len+1==sam[q].len) sam[np].fa=q; else { nq=++tots;sam[nq].init(0); sam[nq]=sam[q]; sam[nq].len=sam[p].len+1; sam[q].fa=nq;sam[np].fa=nq; while(p!=-1&&sam[p].son[w]==q) sam[p].son[w]=nq,p=sam[p].fa; } } last=np; } void build(char* str) { int len=strlen(str); for(int i=0;i<len;++i) extend(str[i]); memset(dp,0,sizeof(dp)); topsort(); } int r[maxn*2],w[maxn]; //r[i]为topsort后 入度为0先入队 void topsort() { int i,len=tots; memset(w,0,sizeof(w)); for(int i=1;i<=tots;++i) w[sam[i].len]++; for(int i=1;i<=len;++i) w[i]+=w[i-1]; for(int i=tots;i>=1;--i) r[w[sam[i].len]--]=i; r[0]=0; } void output() { for(int i=0;i<=tots;++i) { printf("%d(fa=%d): ",i,sam[i].fa); for(int j=0;j<26;++j) if(sam[i].son[j]!=-1) printf("%c(%d) ",j+'a',sam[i].son[j]); printf("\n"); } } void Add(char* str) { int len=strlen(str); int p=root,tmp=0; for(int i=0;i<len;++i) { int id=str[i]-'a'; while(sam[p].fa!=-1&&sam[p].son[id]==-1) { p=sam[p].fa; tmp=sam[p].len; } if(sam[p].son[id]!=-1) { p=sam[p].son[id]; tmp++; } dp[p]=max(dp[p],tmp); } } LL Solve() { LL Ans=0; for(int i=tots;i>=1;--i) { int p=r[i]; int pre=sam[p].fa; dp[pre]=max(dp[p],dp[pre]); dp[pre]=min(dp[pre],sam[pre].len); int tmp=sam[p].len-dp[p]; tmp=min(tmp,sam[p].len-sam[pre].len); Ans+=tmp; } return Ans; } }Sam; char str[maxn]; int main() { int T,Case=0; scanf("%d",&T); while(T--) { Sam.init(); int n; scanf("%d",&n); scanf("%s",str); Sam.build(str); for(int i=1;i<=n;++i) { scanf("%s",str); Sam.Add(str); } LL Ans=Sam.Solve(); printf("Case %d: %lld\n",++Case,Ans); } return 0; }
相关文章推荐
- hdu 4416 Good Article Good sentence(后缀自动机)
- hdu 4416 后缀自动机 求一个字符串中出现的不同子串的个数(去除一些其他字符串的子串)
- hdu 4416 Good Article Good sentence (后缀自动机 SAM)
- HDU 3518 && HDU 4416【后缀自动机len的使用】
- HDU 4416 (后缀自动机)
- HDU 4416 Good Article Good sentence(后缀自动机)
- hdu 4416 后缀自动机 问在S中有多少个不同子串满足它不是s1~sn中任意一个字符串的子串
- hdu4416——后缀自动机
- Hdu 4416 Good Article Good sentence 后缀自动机
- HDU 4416 Good Article Good sentence 后缀自动机
- HDU 4622 Reincarnation 后缀数组 或 后缀自动机
- 【HDU】5470 Typewriter 【后缀自动机+dp】
- HDU 4622 Reincarnation 后缀自动机
- hdu 6208 The Dominator of Strings 后缀自动机 LCS
- hdu 4436 str2int (后缀自动机+dp)
- HDU 4436 (后缀自动机)
- hdu 5008 Boring String Problem(后缀自动机构造后缀树)
- HDU 4622 后缀自动机
- hdu 4622 后缀数组计数问题||后缀自动机
- HDU 1403 Longest Common Substring(后缀自动机——附讲解 or 后缀数组)