zoukankan      html  css  js  c++  java
  • [POI2005]Sza-Template

    Byteasar 想在墙上涂一段很长的字符,他为了做这件事从字符的前面一段中截取了一段作为模版. 然后将反复使用这个模版喷涂到相应的位置后就得到了他想要的字符序列.一个字符可以被喷涂很多次,但是一个位置不能喷涂不同的字符.做一个模版很费工夫,所以他想要模版的长度尽量小,求最小长度是多少.拿样例来说 ababbababbabababbabababbababbaba , 模版为前8个字符ababbaba, 喷涂的过程为:

    Input
    输入一行最多不超过500 000 个最少1个小写字符.

    Output
    一个长度表示模版最小的长度.

    Sample Input
    ababbababbabababbabababbababbaba

    Sample Output
    8

    这道题的问题,其实就是从根节点开始往n号节点走一条链,并且每次把当前节点的fail树子树中的所有节点标记,将这些节点数字用一个双向链表来进行维护,统计原串上的最大空隙,如果空隙小于当前节点代表的前缀的长度,就作为答案输出。如果当前节点不满足则取其子结点(位于链上的),进行上述的操作。此时就要将链表中的没用的点删去。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    char a[500010];int n,cnt,maxgap,fail[500010],pre[500010],suc[500010],first[500010],ans[500010],tot;
    struct edge
    {
    	//fail树上的边
        int to,next;
    }e[500010];
    void add(int u,int v)
    {
        e[++cnt]=(edge){v,first[u]};first[u]=cnt;
    }
    void getfail()
    {//求next数组(我的代码里叫fail)
        int i,j=0;
        for(i=1;i<n;i++)
    	{
            while(j&&(a[i]!=a[j])) 
    		     j=fail[j];
            j+=(a[i]==a[j]);
    		fail[i+1]=j;
        }
        for(i=1;i<=n;i++) 
    	   add(fail[i],i);
    }
    void del(int x)
    {
    	//链表删除操作,O(1)
        suc[pre[x]]=suc[x];
        pre[suc[x]]=pre[x];
        maxgap=max(maxgap,suc[x]-pre[x]);
    	suc[x]=pre[x]=0;
    }
    int q[500010];
    void bfs(int s,int avoid)
    {
    	//s的子树中,避开avoid的子树,其余点全部从链表里面删掉
        int u,v,i,head=0,tail=1;q[0]=s;
        while(head<tail)
    	{
            u=q[head++];
    		if(u==avoid)
    		    continue;
            del(u);
            for(i=first[u];~i;i=e[i].next)
    		{
                v=e[i].to;
    			q[tail++]=v;
            }
        }
    }
    int main()
    {
        memset(first,-1,sizeof(first));
    	memset(fail,0,sizeof(fail));
    	int i,j;
        scanf("%s",a);
    	n=strlen(a);
        getfail();
        for(i=n;i;i=fail[i]) 
    	    ans[++tot]=i;
    	ans[tot+1]=0;
        for(i=1;i<=n;i++) 
    	    pre[i]=i-1,suc[i]=i+1;
        maxgap=1;
        for(i=tot;i>=1;i--)
    	{
            bfs(ans[i+1],ans[i]);
            if(maxgap<=ans[i])
    		{
                printf("%d",ans[i]);return 0;
            }
        }
    }
    

      

  • 相关阅读:
    Unity3D实践系列08, MonoBehaviour类的各种触发事件
    Unity3D实践系列07,组件的启用或禁用开关,物体的的可见或不可见开关,以及相应事件
    Unity3D实践系列06,球体撞击物体游戏
    Linux tee的花式用法和pee
    bash内置命令mapfile:读取文件内容到数组
    Perl正则表达式引用
    Perl文件句柄引用
    透明代理、正向代理、反向代理的区别说明
    Perl回调函数和闭包
    一文搞懂:词法作用域、动态作用域、回调函数、闭包
  • 原文地址:https://www.cnblogs.com/cutemush/p/12706316.html
Copyright © 2011-2022 走看看