zoukankan      html  css  js  c++  java
  • HDU 6230 Palindrome ( Manacher && 树状数组)

    题意 : 给定一个字符串S,问你有多少长度为 n 的子串满足  S[i]=S[2ni]=S[2n+i2(1in)

    参考自 ==> 博客

    分析 : 可以看出满足题目要求的特殊回文子串其实是根据 n 以及 2*n-1 对称的,如图所示

    如果我设第一个对称点为 i 第二个为 j ,p[i] 为以 i 为中心是回文半径, 那满足题目条件的子串必定满足  − p[j≤ ≤ p[i− 1 

    简单点说就是两点的回文半径要相互覆盖

    p[]数组很容易使用 Manacher 算法算出来,那么该如何去找答案?(当时就是想到马拉车,然后完全不知道怎么快速找答案,我好菜啊!)

    我们从小到大枚举 j , 对于它左边的所有的点找出满足条件的 i ,即 i + p[i] >= j ,那么我哪知道 j 左边的哪些点是能够成为满足条件的 i ?

    由于是从小到大更新,我们将枚举过的 j 装进一个根据 j + p[j] 长度升序的优先队列中,然后使用树状数组在 j 这个点更新贡献 + 1

    在枚举下一个 j 的时候,我们将优先队列里面的元素一个个取出来(优先队列里面的元素其实就是现在 j 左边的点),取出来有我们需要去掉不满足条件的点 即 覆盖不到当前 j 的点,直到队头点满足条件或者队列为空,然后对于枚举的每一个 j 贡献出来的答案就是树状数组的前缀和 sun(i) - sum(i-p[i]-1)

    可能说的不太清楚,具体看看代码吧,看完了应该就懂了!

    #include<bits/stdc++.h>
    #define lowbit(i) (i&(-i))
    using namespace std;
    const int maxn = 500000 + 5;
    char s[maxn], sNew[maxn<<1];
    int p[maxn<<1], id, mx=0;
    int c[maxn];
    
    int Init()
    {
        int len = strlen(s);
        sNew[0] = '$';
        sNew[1] = '#';
        int j = 2;
        for (int i = 0; i < len; i++){
            sNew[j++] = s[i];
            sNew[j++] = '#';
        }
        sNew[j] = '';
        return j;
    }
    
    int Manacher()
    {
        int len = Init();
        int max_len = -1;
        mx = 0;
        for (int i = 1; i < len; i++){
            if (i < mx) p[i] = min(p[2 * id - i], mx - i);
            else p[i] = 1;
    
            while (sNew[i - p[i]] == sNew[i + p[i]]) p[i]++;
    
            if (mx < i + p[i]){
                id = i;
                mx = i + p[i];
            }
        }
        return len;
    }
    
    inline void add(int i, int val)
    {
        while(i <= maxn-5){
            c[i] += val;
            i += lowbit(i);
        }
    }
    
    int sum(int i)
    {
        int ret = 0;
        while(i > 0){
            ret += c[i];
            i -= lowbit(i);
        }
        return ret;
    }
    
    struct cmp{
        bool operator () (int &A, int &B) const{
            return A + p[A] > B + p[B];
        };
    };
    priority_queue<int, vector<int>, cmp> que;
    
    int main(void)
    {
        int nCase;
        scanf("%d
    ", &nCase);
        while(nCase--){
            scanf("%s", s);
            int len =  Manacher();
    
            for(int i=1, j=2; j<len; i++,j+=2)
                p[i] = p[j]/2 - 1;
    
            while(!que.empty()) que.pop();
            memset(c, 0, sizeof(c));
            long long ans = 0;
            for(int i=2; i<=(len-1)/2; i++){
               // printf("%d ", p[i]);
                while(!que.empty()){
                    int now = que.top();
                    if(now + p[now] < i){///去掉不合格的点!
                        add(now, -1);
                        que.pop();
                    }else break;
                }
                ans += sum(i) - sum(i-p[i]-1);
                que.push(i);
                add(i, 1);
            }//puts("");
            printf("%lld
    ", ans);
        }
        return 0;
    }
    View Code

    瞎 : 马拉车的 p[ ] 数组还有几个特性!

    p[i]-1 为以 i 为中心的回文长度

    p[i]/2 表示回文半径

    i%2==0 表示这个位置为字符,i/2-1 表示原字符串的位置

    i%2==1 表示为字符中间,这两边的字符在原字符串的位置分别为 i/2-1 和 i/2

  • 相关阅读:
    layer 弹出在 iframe内部弹出不居中是原因
    关于 DropDownList 循环绑定中遇到的问题
    C# Oracle insert 过程中出现中文乱码问题
    使用C#实现sql server 2005 和Oracle 数据同步
    C# mysql 数据库操作模板
    spring jar 包详解、依赖说明
    在js中使用jstl标签给js变量赋值
    maven3 在创建web项目时:Dynamic Web Module 3.0 requires Java 1.6 or newer 错误
    hadoop start-all.sh 启动出错java.lang.ClassNotFoundException: start-all.sh
    jquery easyui datagrid 排序
  • 原文地址:https://www.cnblogs.com/qwertiLH/p/7993710.html
Copyright © 2011-2022 走看看