首页 > 其他分享 >洛谷 P4840 解题报告

洛谷 P4840 解题报告

时间:2022-10-02 20:44:35浏览次数:52  
标签:tot 洛谷 int P4840 len lst 解题 vec mr

洛谷 P4840 解题报告

STEP 1. 题目大意

  • 求字符串 \(S\) 的所有循环同构中本质不同的回文子串数量的最大值。

  • 数据范围 $ |S| \leq 1.5e6 $

STEP 2. 思路分析

看到回文串计数,首先肯定采用 \(PAM\) ,不妨设长度为 \(n\) ,

考虑将 \(S\) 倍长,这样原问题就转化为每一段长度为 \(n\) 的结束位置在后缀树上到根节点路径并的大小。

然而这样不是很好维护,于是我们考虑每次加入一个字符对答案区间贡献的范围,显然开始位置不能在当前回文串的中间某处。

于是在区间 \(\left[ i - n + 1, i - t[x].len + 1\right] \cup \left[ i + 1,n - 1\right]\) 中均可以取 (注意此处忽略了与 \(n\) 大小关系的分类讨论)。

但是如果每次暴力计算区间复杂度会炸,不过我们发现:

当我们把所有的可行区间合并在一起时,最终总区间不会多于 \(2\) 个。

这是因为每个回文子串至多被删除一次,然后又添加一次。

所以我们只需在回文树上暴力向父节点上传信息即可,注意上传时维护区间端点。

STEP 3. 复杂度分析

如果采用 \(\text {vector}\) 实现,并且即时更新区间,

复杂度为 \(O(|\Sigma| \times n) + O(n)\)

如果使用 \(\text {sort}\) ,那么复杂度为 \(O(|\Sigma| \times n) + O(n \times \log n)\)

不过众所周知 \(PAM\) 常数很大,所以得开 \(O2\) 。

STEP 4. 代码实现

#include <bits/stdc++.h>
#define For(i, a, b) for (int i = a; i <= b; ++i)
#define Rep(i, a, b) for (int i = a; i >= b; --i)
using namespace std;
const int maxN = 3000005;
int n, ans, tot = 1, in[maxN], d[maxN];
struct PAM {
  int ch[26], fail, len;
}t[maxN];
char s[maxN];
vector<pair<int, int> >vec[maxN];
queue<int> q;
int getf(int x, int pos) {
  while (pos - t[x].len - 1 < 0 || s[pos - t[x].len - 1] != s[pos]) x = t[x].fail;
  return x;
}
int main() {
  scanf("%s", s);
  n = strlen(s); t[0].fail = 1; t[1].len = -1;
  For (i, 0, n - 1) s[i + n] = s[i];
  int lst = 0;
  For (i, 0, n * 2 - 1) {
    int tr = getf(lst, i);
    if (!t[tr].ch[s[i] - 'a']) {
      ++tot; t[tot].fail = t[getf(t[tr].fail, i)].ch[s[i] - 'a'];
      t[tr].ch[s[i] - 'a'] = tot;
      t[tot].len = t[tr].len + 2;
      ++in[t[tot].fail];
    }
    lst = t[tr].ch[s[i] - 'a'];
    vec[lst].emplace_back(max(0, i - n + 1), min(i - t[lst].len + 1, n));
    vec[lst].emplace_back(i + 1, n - 1);
  } // PAM与区间更新
  For (i, 2, tot)
    if (!in[i]) q.emplace(i);
  while (!q.empty()) {
    int x = q.front(); q.pop();
    sort(vec[x].begin(), vec[x].end());
    vector<pair<int, int> >nw;
    int ml = 0, mr = -1;
    for (auto s : vec[x]) {
      if (s.first > mr) {
        if (mr >= 0) nw.emplace_back(ml, mr);
        ml = s.first; mr = s.second;
      }
      mr = max(s.second, mr);
    }
    if (mr >= 0) nw.emplace_back(ml, mr); // 合并当前区间
    swap(nw, vec[x]);
    for (auto s : vec[x]) {
      if (t[x].len > 0 && t[x].len <= n) { 
        ++d[s.first]; --d[s.second + 1]; 
      } // 差分统计答案
      vec[t[x].fail].emplace_back(s.first, min(s.second - t[t[x].fail].len + t[x].len, n));
    }
    vec[x].clear(); vec[x].shrink_to_fit();
    if (!--in[t[x].fail]) q.emplace(t[x].fail);
  }
  int ans = d[0];
  For (i, 1, n - 1) {
    d[i] += d[i - 1];
    ans = max(ans, d[i]);
  }
  cout << ans;
  return 0;
}

标签:tot,洛谷,int,P4840,len,lst,解题,vec,mr
From: https://www.cnblogs.com/LitDarkness/p/16749411.html

相关文章

  • 洛谷P3375 kmp字符串匹配
    #include<bits/stdc++.h>#defineintlonglongusingnamespacestd;inti,j,k,la,lb,kmp[1000005];chara[1000005],b[1000005];signedmain(){  scanf("%s%s",......
  • 洛谷 P1506 拯救oibh总部(DFS / 染色法)
    https://www.luogu.com.cn/problem/P1506题目描述给定n*m的图形,由*和0组成。让我们求出被*四面包围了的0的数量。输入#1450000000*000*0*000*00输出......
  • 洛谷 P2709 小B的询问 题解
    莫队板子。//P2709小B的询问#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;constintMAXN=50005;structQuery{ intl,r,id;}q[MAXN];in......
  • 洛谷 P2419 [USACO08JAN]Cow Contest S(最短路:floyed)
    https://www.luogu.com.cn/problem/P2419题目大意:给定n头奶牛(1<=N<=100),按1..N依次编号。m轮:两两之间进行对决,赢了的排在左边,输了的排在右边。我们想知道奶牛们编......
  • 洛谷P8551 Bassline 题解
    P8551Bassline题解分析这道题做月赛的时候想了好久,最后发现其实很简单。我们用样例数据来分析:如图所示,我们将每个区间抽象化为一个一个的长条。题目给我们的两个要......
  • 洛谷 P7861 SAVEZ 题解(哈希)
    2020牛客杯NOIP赛前集训提高第一场T2牛牛的猜球游戏题解目录2020牛客杯NOIP赛前集训提高第一场T2牛牛的猜球游戏题解比赛链接题目题目描述输入格式输出格式样例样例......
  • P2671 [NOIP2015 普及组] 求和(洛谷前缀和
    P2671[NOIP2015普及组]求和1//(x+z)*(num[x]+num[z])=2//(x1+x2)*(y1+y2)+(x1+x3)*(y1+y3)+(x2+x3)*(y2+y3)3//=x1*(y1*(n-2)+y1+y2+...+yn)4//+x2*(y2*......
  • 洛谷 P3193 [HNOI2008]GT考试
    原题链接dp+矩阵加速明天再来写#pragmaGCCoptimize(2)#include<bits/stdc++.h>usingnamespacestd;#definefrfirst#definesesecond#defineet0exit(0);#......
  • 洛谷 P1164 小A点菜(DP:01背包)
    https://www.luogu.com.cn/problem/P1164题目大意:给定n种菜品(每种菜品只有1份),m块钱;问我们花完了这m块钱可以点的不同种类的菜品有多少种方案数?输入441122输......
  • 洛谷 P1667
    这种奇怪的在数列上操作,看看在前缀和/差分数组上发生了什么事往往能发现新大陆。考虑\(a\)的前缀和\(S\),不难发现操作\([l,r]\)就是交换\(S_{l-1},S_r\)。所以最......