spoj 8222 Substrings(NSUBSTR),后缀自动机
来源:互联网 发布:民间借贷知乎 编辑:程序博客网 时间:2024/06/10 04:32
spoj 8222 Substrings
f[i]指长度为i的串出现次数的最大值。这里的不同出现指,可以有重复串,只要起始位置不同就视为不同的出现。
求f[1]..f[lenth]。
怎么求可重复的一个串出现了多少次。
LCS那篇里提到了,通过fa指针回退,会回到一个状态,这个状态的接受串与当前状态的接受串后缀是相同的。
那么,设t[i].fa=j,那么i状态的接受串也必定出现在j状态的接受串的后缀中。又注意到ij的接受串的结束位置是不同的,这样,i状态至少出现了两次。
通过这样的规律,通过fa边的拓扑序dp统计答案即可。
还有一点,一个状态的接受串有可能有多种。如aab,b有可能被同一个状态接受。
如果aab出现了n次,那么b也可能出现n次。而aab的任意子串如aa、ab也出现n次。
这样只需要从最长到最短更新dp的值,就可以不漏掉任何情况。
WA了很久,一直卡在一个地方。翻了很多题解才有所进展。
做初始化时,dp[i]不能全部置为1,而是当i不是分裂的节点(就是构造函数中的nq)这样的节点才置1。
很容易想到,一个节点分裂了,如果都置1,父节点会重复计算。
但是该分裂节点如何保证正确计数?因为构造中,新分裂的节点nq会成为q的父亲,因此q的计数也会加到nq上,就保证了计数的正确。
huyuncong这位大牛写的后缀自动机性质很棒。网址如下:
http://blog.csdn.net/huyuncong/article/details/7583214
引用并补充大牛博客的总结:
一个串的子串有多少之类的问题,或是询问子串/后缀的问题,就用子边转移(自动机性质)。
而计算一个串重复出现次数(right集合的问题),回退到最长匹配状态(LCS问题),就用父边转移(后缀树性质)。
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define Maxn 250009int root,last;//samint tots;struct sam_node{ int fa,son[26]; int len; void init(int _len){len=_len;fa=-1;memset(son,-1,sizeof(son));}}t[Maxn*2];//length*2void sam_init(){ tots=0; root=last=0; t[tots].init(0);}void extend(int w){ int p=last; int np=++tots;t[tots].init(t[p].len+1); int q,nq; while(p!=-1&&t[p].son[w]==-1){t[p].son[w]=np;p=t[p].fa;} if (p==-1) t[np].fa=root; else{ q=t[p].son[w]; if (t[p].len+1==t[q].len){t[np].fa=q;} else{ nq=++tots;t[nq].init(0); t[nq]=t[q]; t[nq].len=t[p].len+1; t[q].fa=nq;t[np].fa=nq; while(p!=-1&&t[p].son[w]==q){t[p].son[w]=nq;p=t[p].fa;} } } last=np;}int w[Maxn],r[Maxn*2],l;void topsort(){ int i; for(i=0;i<=l;++i) w[i]=0; for(i=1;i<=tots;++i)w[t[i].len]++; for(i=1;i<=l;++i) w[i]+=w[i-1]; for(i=tots;i>=1;--i)r[w[t[i].len]--]=i; r[0]=0;}int dp[Maxn*2],f[Maxn];char s[Maxn];int main(){ int i,p; scanf("%s",s); l=strlen(s); sam_init(); for(i=0;i<l;++i){ extend(s[i]-'a'); } topsort(); //for(i=0;i<=tots;++i) {dp[i]=1;} //wrong initializing for(i=0;i<=tots;++i) {dp[i]=0;} p=root; for(i=0;i<l;++i){ p=t[p].son[s[i]-'a']; dp[p]++; } for(i=tots;i>=1;--i){ p=r[i]; if (t[p].fa!=-1) dp[t[p].fa]+=dp[p]; } for(i=1;i<=l;++i) f[i]=0; for(i=1;i<=tots;++i) if (dp[i]>f[t[i].len]) f[t[i].len]=dp[i]; for(i=l-1;i>=1;--i){ f[i]=f[i]<f[i+1]?f[i+1]:f[i]; } for(i=1;i<=l;++i){ printf("%d\n",f[i]); } return 0;}
- spoj 8222 Substrings(NSUBSTR),后缀自动机
- SPOJ 8222 NSUBSTR - Substrings (后缀自动机)
- SPOJ NSUBSTR Substrings 后缀自动机
- SPOJ - NSUBSTR Substrings 后缀自动机
- SPOJ 题目 8222 NSUBSTR - Substrings(后缀自动机+DP求子串出现最大次数)
- SPOJ 8222 NSUBSTR 后缀自动机
- SPOJ NSUBSTR(后缀自动机)
- 【后缀自动机】 SPOJ NSUBSTR
- [SPOJ8222]NSUBSTR - Substrings(后缀自动机)
- SPOJ 8222 NSUBSTR Substrings
- spoj 8222 Substrings(后缀自动机)
- spoj 8222 Substrings (后缀自动机)
- spoj 8222 substrings 【后缀自动机】
- 后缀自动机1002 SPOJ NSUBSTR
- SPOJ NSUBSTR 后缀自动机+DP
- SPOJ Substrings --后缀自动机
- spoj Substrings【后缀自动机】
- SPOJ NSUBSTR(Substrings-后缀自动机统计串出现次数-Right集合&Parent树の暴走)
- 《STL源码剖析》---stl_hashtable.h阅读笔记
- 几种常见web 容器比较 (tomcat、 jboss 、resin、 weblogic、 websphere、 glassfish)
- 【瞎搞】HDU 3257 Hello World!
- PAT_B_结构-04. 通讯录的录入与显示(10)
- Cstring使用说明
- spoj 8222 Substrings(NSUBSTR),后缀自动机
- 2014 Multi-University Training Contest 8 B Area of Mushroom解题报告
- 我希望我56岁的时候还能编程
- 如何把java项目发布到Web容器(Tomcat)中
- 【HDU】1822 Building roads 2-sat
- 在Linux中创建静态库.a和动态库.so
- [编程之美] PSet3.6 编程判断两个链表是否相交
- poj1195
- Tomcat简介