zoukankan      html  css  js  c++  java
  • 【做题】BZOJ2342 双倍回文——马拉车&并查集

    题意:有一个长度为(n)的字符串,求它最长的子串(s)满足(s)是长度为4的倍数的回文串,且它的前半部分和后半部分都是回文串。

    (n leq 5 imes 10^5)

    首先,显然要用manacher求出以每一位为中心的最长回文串。考虑枚举(s)最中间的一个位置(i),且以其为中心的最长回文串长度为(2 r_i),那么,前半部分的中心(j)就必须在([i - lfloor frac {r_i} {2} floor,i))的区间上,并且(i - j leq r_j)。当然,我们会贪心地选择这个区间上最左边的合法的(j)。并且,只要某个(j)在当前中心为(i)的时候满足(i - j leq r_j),那么,对于所有(k leq i),都有(k - j leq r_j)

    于是,只要从左往右移动(i),每次删除移动后非法的(j),问题就变成实现一个数据结构,支持:

    • 删除一个元素
    • 求一个值后继

    这可以轻易地以(O(n log n))的时间复杂度实现,但我们希望一个更优的算法。

    考虑一个元素如果每删除了,那么受影响的就只有以它为后继的值。这些值的后继会变成它们后继的后继。设(S_i)表示以元素(i)为后继的所有值的集合,那么,删除(i)后,我们只要把(S_i)合并到(S_j)里面就可以了。(元素(j)是元素(i)的后继)

    因此,我们用并查集维护一下就好了。这个巧妙的技巧应该会在本题卡常时发挥作用。

    时间复杂度(O(n alpha(n)))

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 500010;
    int n,len[N * 2],r[N];
    char s[N];
    void manacher() {
      for (int i = 2 ; i <= (n << 1) ; ++ i) {
        int l = i >> 1, r = (i + 1) >> 1;
        while (s[l - len[i]] == s[r + len[i]] && l - len[i] >= 1 && r + len[i] <= n)
          ++ len[i];
        l = i - 1, r = i + 1;
        while ((l >> 1) - len[l] > (i >> 1) - len[i] && l >= 1 && r <= 2 * n)
          len[r++] = len[l--];
        len[r] = ((i + 1) >> 1) + len[i] - ((r + 1) >> 1);
        i = r - 1;
      }
    }
    int uni[N],ans;
    vector<int> vec[N];
    int getfa(int pos) {
      return pos == uni[pos] ? pos : uni[pos] = getfa(uni[pos]);
    }
    int main() {
      scanf("%d",&n);
      scanf("%s",s+1);
      manacher();
      for (int i = 1 ; i <= n ; ++ i)
        r[i] = len[i << 1 | 1];
      for (int i = 1 ; i <= n ; ++ i)
        uni[i] = i;
      for (int i = 1 ; i < n ; ++ i) {
        int k = i - (r[i] >> 1);
        ans = max(ans,4 * (i - getfa(k)));
        vec[i + r[i]].push_back(i);
        for (int j = 0 ; j < (int)vec[i].size() ; ++ j)
          uni[vec[i][j]] = vec[i][j] + 1;
      }
      printf("%d
    ",ans);
      return 0;
    }
    

    小结:对一些简单的小技巧还是不熟悉。或许是平庸的大数据结构做多了的问题吧。做题策略要调整。

  • 相关阅读:
    7-10 社交网络图中结点的“重要性”计算(30 point(s)) 【并查集+BFS】
    7-5 打印选课学生名单(25 point(s)) 【排序】
    7-3 堆栈模拟队列(25 point(s)) 【数据结构】
    7-5 家谱处理(30 分) 【数据结构】
    7-7 最强素数(100 分) 【前缀和】
    PAT 天梯赛 L2-022. 重排链表 【数据结构】
    7-1 列出叶结点(25 分) 【数据结构】
    7-6 公路村村通(30 分) 【prime】
    PAT 甲级 1116. Come on! Let's C (20) 【循环判断】
    PAT 甲级 1104. Sum of Number Segments (20) 【数学】
  • 原文地址:https://www.cnblogs.com/cly-none/p/9379566.html
Copyright © 2011-2022 走看看