首页 > 其他分享 >CF1827C Palindrome Partition 题解

CF1827C Palindrome Partition 题解

时间:2024-03-01 10:00:42浏览次数:23  
标签:Palindrome int 题解 len MAXN CF1827C cv dp 回文

CF1827C Palindrome Partition 题解

题面

题目传送门

称一个字符串是 好的,当且仅当它是一个长度为偶数的回文串或由若干长度为偶数的回文串拼接而成。

给定一个长度为 \(n\) 的字符串 \(s\),求有多少 \(s\) 的子串是好的。

$ 1 \le n \le 5 \cdot 10^5$, \(s\) 仅包含小写字母。

与 CSP-S 2023 T2 的区别

千万不要说这两题重了,免得别人来笑话。

举一个例子,abbcca,可以思考一下。

分析

那么这题多半是只能老老实实去找回文串。考虑使用回文树

先来分析回文串的性质。

  • 设 \(s[l,r]\) 为回文串,若 \(s[x,r]\) 也为回文串(\(\left\lfloor \frac{l+r+1}{2}\right\rfloor \le x \le r\))。
  • 则 \(s[l,l+(r-x+1)-1]\) 也为回文串(因为整体回文,所以右边会问则左边也回文)
  • 则 \(s[l+(r-x+1),x-1]\) 也为回文串(因为整体回文)

如果通过第一个假设,判断 \(s[l,r]\) 是 好的 就不需要判断 \(s[l,r]\) 是否回文,只用判断它内部是否可以组成。

思路

我们知道在字符串位置 \(i\),在回文树位置 \(j\),只用不断跳后缀链接,设当前位置回文串的长度为 \(l\),则 \(s[i-l+1,i]\) 为回文串。

设对于所有 \(l\) 为偶数,组成一个序列 \(L_1<L_2<L_3<\cdots<L_k\),那么 \(s[i-L_x+1,i]\) (\(2 \le x \le k\))必定可以被除自己的回文串组成(通过分析容易知道)。

那么我们只用对于每个 \(i\) 找到 \(L_1\)(可以用路径压缩来解决满足复杂度要求),则 \(dp_i=dp_{L_1}+1\),若没有 \(L_1\),则 \(dp_i=0\)。

最后答案为 \(\sum_{x=1}^{n}{dp_x}\)。

时间复杂度 \(O(n \log n)\),瓶颈在找到 \(L_1\)。

Code

#include <bits/stdc++.h>

using namespace std;
using LL = long long;
using Pair = pair<LL, LL>;

const int MAXN = 1e6 + 3;

int n;
string s;
int trie[MAXN][26], cv = 1, len[MAXN], _len[MAXN], pos[MAXN]/*原串中出现位置*/, nxt[MAXN]/*后缀链接*/;
int fa[MAXN];
LL dp[MAXN], ans = 0;

int Getf(int x){
  if(fa[x] <= 1|| fa[x] == x || Getf(fa[x]) == 0 || _len[Getf(fa[x])] == 0){
    return (len[x] % 2 == 0 ? fa[x] = x : fa[x] = 0);
  }else return fa[x] = Getf(fa[x]);
}

int main(){
  ios::sync_with_stdio(0), cin.tie(0);
  int T;
  cin >> T;
  while(T--){
    cin >> n >> s, s = " " + s;
    for(int i = 0; i <= cv; i++){
      for(int col = 0; col < 26; col++) trie[i][col] = 0;
    }
    cv = 1;
    ans = 0;
    _len[0] = len[0] = -1, nxt[0] = 0, _len[1] = len[1] = 0, nxt[1] = 0;
    for(int i = 1, j = 1 /* i-1 的后缀的最长回文后缀对应回文树上的节点编号 */; i <= n; i++){
      while(s[i] != s[i - len[j] - 1]) j = nxt[j];
      if(!trie[j][s[i] - 'a']){
        trie[j][s[i] - 'a'] = ++cv;
        _len[cv] = len[cv] = len[j] + 2;
        pos[cv] = i - len[cv] + 1;
        for(int &k = (nxt[cv] = nxt[j]); s[i] != s[i - len[k] - 1]; k = nxt[k]);
        // 也可以写成 for(int &k = nxt[cv] = nxt[j]; s[i] != s[i - len[k] - 1]; k = nxt[k]);

        if(len[cv] > 1) fa[cv] = nxt[cv] = trie[nxt[cv]][s[i] - 'a'];
        else fa[cv] = nxt[cv] = 1;
      }
      j = trie[j][s[i] - 'a'];
      if(Getf(j) != 0) _len[j] = _len[Getf(j)];
      else _len[j] = 0;
      dp[i] = (_len[j] == 0 ? 0 : dp[i - _len[j]] + 1), ans += dp[i];
    }
    cout << ans << "\n";
  }
  return 0;
}
/*
6
abaaba
1 2 1 1 1
1 2 0 1 1**
2 3 1 1 1
2 3 0 1 1**
3 4 2 2 3
3 4 0 2 3**
4 5 2 2 2
*/

标签:Palindrome,int,题解,len,MAXN,CF1827C,cv,dp,回文
From: https://www.cnblogs.com/huangqixuan/p/18046310

相关文章

  • P6185 序列 题解
    如果发现自己莫名其妙错了,可能是代码UB,还开O2!!!!!!!!!!!传送门首先,对于每个操作2,将\(u_i,v_i\)连边。连边之后每个连通块内部可以在总和不变的情况下任意改变。用并查集将每个连通块缩点,然后对于每个操作1,将\(u_i,v_i\)连边。得到的图又会分成若干个连通块。判断整个图是否可行,只......
  • [ABC238F] Two Exams 题解
    [ABC238F]TwoExams题解思路解析这题很麻烦,因为有两个维度。所以可以想到先按照第一维排序,这样就不需要考虑第二维的问题。其次再发现数据范围小,可以想到能用dp做,接下来就考虑如何dp。首先我们要知道我们遍历到了第几个公民,同时还要知道还剩下几个代表名额,同时我们还需要思......
  • P8085 [COCI2011-2012#4] KRIPTOGRAM 题解
    P8085[COCI2011-2012#4]KRIPTOGRAM题解本文原发布于2024-02-07洛谷题库P8085[COCI2011-2012#4]KRIPTOGRAM题解区,现于2024-2-29转载至博客园思路解析这道题目的主要难点在于如何判断明文中形如\(\texttt{abcb}\)的子串可以和密文\(\texttt{bcac}\)匹配,因为如果......
  • 个人题解:江苏省选 2019 第二轮
    精准预测我们首先发现每个人每个时刻只有生死,所以我们可以建一个2-sat模型。每个人对应\(T+1\)个节点,表示这个人在每个时刻的生死。那么,题目的条件可以直接在这个模型上面建图,还要注意第\(t\)秒死亡可推出第\(t+1\)秒死亡和第\(t+1\)秒存活能推出第\(t\)秒存活的两......
  • 后端项目打包相关问题解决
    在对项目进行打包后,我运行jar包发现出现下面错误:nomainmanifestattribute,in"app.jar" 在“app.jar”中没有主清单属性说明jar包里面的META-INF/MANIFEST.MF文件中没有Main-Class这个属性于是我解压jar包,到META-INF/MANIFEST.MF文件中手动添加了Main-Class: com.xxx.xx......
  • 2024年2月29号题解
    P1014[NOIP1999普及组]Cantor表解题思路和之前的蛇蝎矩阵很像,因此可以先构建一个蛇蝎矩阵因为是z形所以在每个奇数次矩阵的对角线进行交换就可以了,这样就得到了我们需要的矩阵代码实现#define_CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<stdlib.h>#inclu......
  • 题解 CF1709 XOR
    *2400*dsuontree一道很好的题目思路很巧妙传送门题目大意给出一棵树,\(n\)个节点,每个节点有权值\(v\),定义一次操作为修改任意一个节点的值为任意正整数,要求最后的树不存在任意简单路径使得路径异或和为\(0\)Solution一个很常用的套路,先钦定根节点为\(1\)定义\(w......
  • CF1265E Beautiful Mirrors 题解
    CF1265EBeautifulMirrors题解题目大意题目传送门你有\(n\)个点,当你在第\(i\)个点时,有\(p_i\)的概率到达点\(i+1\),有\(1-p_i\)的概率回到点1。当到达点\(n+1\)时,游戏结束。且期望进行的游戏次数。\(1\len\le2\times10^5\)。题目分析设\(f_i\)表示到达点\(......
  • P2606 [ZJOI2010] 排列计数 题解
    题意:求有多少个排列满足:对于每一个\(2\lei\len\),\(a_i>a_{\frac{i}{2}}\)。首先我们会发现这些数之间的大小关系形成了一个完全二叉树,因为每一个\(a_i\)都必须小于\(a_{2\timesi}\)和\(a_{2\timesi+1}\)。会发现本题的方案和每个位置具体的值并没有关系,而只......
  • 打击犯罪(题解)
    题目题目描述样例输入722531342242233167257256样例输出1关于本题这个题反着想会很简单,也就是复活犯罪,但是这个反着的思路不好想到(比如我就没想到)。看其他blog基本上都是反着来的,确实复杂度小不少,但是别人写过的我就不写了,我就给出正着来的解......