• 2015 UESTC Training for Search Algorithm & String


    O(n)的复杂度求回文串:Manacher算法

    定义一个回文值,字符串S是K重回文串,当且仅当S是回文串,且其长度为N/2的前缀和长度为N/2的后缀是K1重回文串

    现在给一个2*10^6长度的字符串,求其每个前缀的最大回文值之和。

    设dp[i]为长度为i的前缀的最大回文值。

    当长度为i的前缀的字符串是回文串的时候,有:dp[i]=dp[i/2]+1

    若不是回文串 dp[i]=0

    接下来就是怎么样快速的判断回文串了,推荐算法Manacher算法。

    Manacher算法先对字符串进行修改 如 aba -> $#a#b#a#

    那么该怎么用DP求?

    显然一下几点是满足的:

    如果某个前缀是回文串,该前缀的末端一定是字符#,(因为第一个符号是#)

    故对于不是字符#的位置,它的dp值一定为0

    如果最大延伸数组p[i]=i,即向左正好延伸到最左边,那么1~p[i]+i-1一定是一个回文前缀

    若第i位是#号 : dp[mx]=dp[i]  其中mx=p[i]+i-1 

    对于不是#的情况 : dp[mx]=dp[i-1] 其中mx=p[i]+i-1

    #include<bits/stdc++.h>
    #define eps 1e-9
    #define FOR(i,j,k) for(int i=j;i<=k;i++)
    #define MAXN 4000005
    #define MAXM 40005
    #define INF 0x3fffffff
    #define PB push_back
    #define MP make_pair
    #define X first
    #define Y second
    #define lc (k<<1)
    #define rc ((k<<1)1)
    using namespace std;
    typedef long long LL;
    int i,j,k,n,m,x,y,T,ans,big,cas,num,len;
    bool flag;
    
    int p[MAXN],dp[MAXN];
    char str[MAXN],s[MAXN];
    
    void kp()
    {
        int i;
        int mx = 0;
        int id;
        for(i=n; str[i]!=0; i++)//清除n后边多余的部分
            str[i] = 0; //没有这一句有问题。。就过不了ural1297,比如数据:ababa aba
        for(i=1; i<n; i++)
        {
            if( mx > i )
                p[i] = min( p[2*id-i], p[id]+id-i );
            //因为是从左往右扫描的这里i>id, 2*id-i是i关于id的对称点,该对称点在id的左端
            //p[id]+id是描述中的mx,即id向右延伸的端点位置
            //显然向右延伸是可能超出mx的,所以要有下边的for循环
            else
                p[i] = 1;
            for(; str[i+p[i]] == str[i-p[i]]; p[i]++);
    
            if( p[i] + i > mx )//更新mx与id,因为mx是向右延伸的最大长度,所以实时更新
            {
                mx = p[i] + i;
                id = i;
            }
        }
    }
    
    void init()//处理字符串
    {
        int i, j, k;
        str[0] = '$';
        str[1] = '#';
        for(i=0; i<n; i++)
        {
            str[i*2+2] = s[i];
            str[i*2+3] = '#';
        }
        n = n*2+2;
        s[n] = 0;
    }
    
    int main()
    {
        scanf("%s",s);
        n=strlen(s);
        init();
        kp();
        for (i=2;i<n;i++)
        {
            if (p[i]==i)
            {
                int mx=p[i]+i-1;
                if (str[i]!='#')
                {
                    dp[mx]=max(dp[mx],dp[i-1]+1);
                }else
                    dp[mx]=max(dp[mx],dp[i]+1);
            }
        }
        int sum=0;
        for (i=0;i<n;i++) sum+=dp[i];
        printf("%d
    ",sum);
        return 0;
    }

     

  • 相关阅读:
    复制文字时自动加版权
    Linux安装Docker
    ThreadLocal 理解
    Spring多数据源动态切换
    [LOJ#500]「LibreOJ β Round」ZQC的拼图
    [JLOI2015]装备购买
    「雅礼集训 2017 Day4」洗衣服
    [BJWC2011]元素
    [51nod1577]异或凑数
    [ARC101B]Median of Medians
  • 原文地址:https://www.cnblogs.com/zhyfzy/p/4477556.html
Copyright © 2020-2023  润新知