bzoj-1535 Sza-Template

来源:互联网 发布:淘宝一分钱试用在哪里 编辑:程序博客网 时间:2024/05/29 15:45

题意:

给出一个长度为n的字符串,求用它的一个子串作为模板能粘贴出整个字符串的最小长度;

n<=500000;


题解:
首先我们可以知道,这个模板串一定是既为原串的一个前缀也为它的一个后缀的,否则并不能拼出来这个字符串

那么利用KMP或AC自动机构建出fail树,答案只可能出现在树中(root,n]这条路径上;

那么问题就是:枚举树上的每一个点(也是串中的一个前缀),判断它是否能覆盖整个字符串,能的话更新答案;

这步转化之后复杂度没有改变,但是fail树上还有另一个性质:一个点代表的字符串是这个点的子树中所有点的后缀,且拥有这个后缀的所有串都在子树内;

因此我们只要维护这个子树中相邻两个匹配点的最大间隔,判断与原串的大小关系就可以了;

从根向下枚举,利用子树集合单调性,用一个链表维护子树元素即可;

每个元素只会被删除一次,所以总复杂度是O(n)的;


%%%JCVB

顺便我又忘了KMP咋写了啊啊啊


代码:


#include<stdio.h>#include<string.h>#include<algorithm>#define N 510000using namespace std;char str[N];int fail[N];int next[N],to[N],head[N],ce;int son[N],L[N],R[N];void getfail(int n){int i=1,j=0;fail[1]=0;while(i<=n){if(j==0||str[i]==str[j]){i++,j++;fail[i]=j;}elsej=fail[j];}}void add(int x,int y){to[++ce]=y;next[ce]=head[x];head[x]=ce;}void dfs(int x,int &len){R[L[x]]=R[x];L[R[x]]=L[x];len=max(R[x]-L[x],len);L[x]=0x3f3f3f3f;for(int i=head[x];i;i=next[i])dfs(to[i],len);}int main(){int n,m,i,j,k,ans,len;scanf("%s",str+1);n=strlen(str+1);getfail(n);for(i=1;i<=n;i++)fail[i]=fail[i+1]-1,add(fail[i],i);i=n;while(fail[i]){son[fail[i]]=i;i=fail[i];}son[0]=i;for(i=1;i<=n;i++){L[i]=i-1;R[i]=i+1;}for(i=0,ans=n,len=1;i!=n;){for(j=head[i];j;j=next[j]){if(to[j]!=son[i]){dfs(to[j],len);}}i=son[i];if(len<=i)ans=min(ans,i);}printf("%d\n",ans);return 0;}



1 0
原创粉丝点击