无从追溯的一道题目。。

题目大意:给出一个字符串 s,要求在 s 中选出3个互不相交的回文子串,求长度之和的最大值

题目分析:考虑 n * n 的 dp,dp[ i ][ k ] 为 s[ 1 : i ] 的前缀中,选出了 j 个回文子串的最大长度,转移的话也比较简单,先对字符串建立回文自动机,枚举以点 i 为结尾的所有回文子串,设枚举到的节点为 p:

  1. k == 1:dp[ i ][ 1 ] = len[ p ]
  2. k == 2 || k == 3:dp[ i ][ k ] = max( dp[ i ][ k ] , dp[ i - len[ p ] ][ k - 1 ] + len[ p ] )

接下来考虑 Palindrome Series 优化,对于上述方程换一种表达方式,设 j 为下标,满足 s[ j : i ] 为回文子串,那么 dp[ i - len[ p ] ][ k - 1 ] + len[ p ] 就等价于 dp[ j ][ k - 1 ] + i - j,所以我们只需要维护一下 dp[ j ][ k - 1 ] - j 的最大值用于更新即可

代码;

//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e6+100;char s[N];int n;LL f[N][4],g[N][4];struct Palindrome_tree
{int nxt[N][26];int fail[N]; // 当前节点最长回文后缀的节点int len[N]; // 当前节点表示的回文串的长度int cnt[N]; // 当前节点回文串的个数, 在getcnt后可得到全部int sed[N]; // 以当前节点为后缀的回文串的个数(并不是表示第i结尾的回文串的种类数,如果要求每个点结尾的数的回文串个数,得用last)int record[N]; //record记录了节点回文串的结束位置int diff[N],anc[N];char s[N];int tot; // 节点个数int last; // 上一个节点int n;//当前字符串的长度 void newnode(){tot++;memset(nxt[tot],0,sizeof(nxt[tot]));cnt[tot]=sed[tot]=len[tot]=fail[tot]=0;}void init(){n=0;tot=-1;newnode();newnode();len[0] = 0, len[1] = -1; // 0为偶数长度根, 1为奇数长度根tot = 1, last = 0;fail[0] = 1;}int getfail(int x, int n){while (s[n - len[x] - 1] != s[n]||n-len[x]-1<0) // 比较x节点回文串新建两端是否相等//n-len[x]-1<0这个是我自己加的,多组的时候光第一个条件是不够的,所以有错请手动删除x = fail[x]; // 若不同, 再比较x后缀回文串两端return x;}void insert(char ch){int c = ch - 'a';//全小写要用a 全大写要用A 不然会错s[++n]=ch;int p = getfail(last, n);// 得到第i个字符可以加到哪个节点的两端形成回文串if (!nxt[p][c]){newnode();len[tot] = len[p] + 2;  // 在p节点两端添加两个字符fail[tot] = nxt[getfail(fail[p], n)][c]; //tot点的后缀回文,可以由上一个节点的后缀回文尝试得到sed[tot] = sed[fail[tot]] + 1; // 以当前节点为结尾的回文串个数nxt[p][c] = tot; // 新建节点diff[tot]=len[tot]-len[fail[tot]];anc[tot]=diff[tot]==diff[fail[tot]]?anc[fail[tot]]:fail[tot];}last = nxt[p][c]; // 当前节点成为上一个节点cnt[last]++; //当前节点回文串++record[last] = n;trans(n);}void trans(int i){for(int k=1;k<=3;k++){f[i][k]=f[i-1][k];for(int j=last;j>1;j=anc[j]){g[j][k]=f[i-len[anc[j]]-diff[j]][k]-(i-len[anc[j]]-diff[j]);if(diff[j]==diff[fail[j]])g[j][k]=max(g[j][k],g[fail[j]][k]);if(k==1)f[i][k]=len[j];elsef[i][k]=max(f[i][k],g[j][k-1]+i);}}}void get_cnt(){for (int i = tot; i > 0; i--)cnt[fail[i]] += cnt[i];//fail[i] 的节点 为 i 节点的后缀回文串, 所以个数相加}
}tree;int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);tree.init();scanf("%s",s+1);n=strlen(s+1);for(int i=1;i<=n;i++)tree.insert(s[i]);printf("%lld\n",f[n][3]);return 0;
}

2019ICPC(沈阳) (回文自动机+Palindrome Series优化dp)相关推荐

  1. CodeForces - 17E Palisection(回文自动机/Palindrome Series优化dp)

    题目链接:点击查看 题目大意:给出一个长度为 n 的字符串,问有多少 相交的回文子串对数 题目分析:背 PAM 模板的时候突然发现了一道模板题,于是顺手写了..正难则反,可以先求出有多少个互不相交的回 ...

  2. CodeForces - 906E Reverses(回文自动机+Palindrome Series优化dp)

    题目链接:点击查看 题目大意:给出两个字符串 s 和 t,每次可以在字符串 s 中选择数个不相交的字串进行反转,问最少需要反转多少次,可以使得字符串 s 和 t 相等,输出最小反转次数以及方案 题目分 ...

  3. CodeForces - 932G Palindrome Partition(回文自动机+Palindrome Series优化dp)

    题目链接:点击查看 题目大意:给出一个长度为偶数的字符串,问将其分割成 k 个子串记为 a[ 1 ] , a[ 2 ] ... a[ k ] ,且满足 a[ i ] == a[ k - i + 1 ] ...

  4. SPOJ - IITKWPCE Let us play with strings(回文自动机+Palindrome Series优化dp)

    题目链接:点击查看 题目大意:给出一个长度为 n 的字符串,问最少拆分成多少个连续的子串,使得每个子串都是一个回文串 题目分析:dp[ i ] 代表 s[ 1 : i ] 的前缀最少可以拆分成多少个连 ...

  5. 怎么判断一个字符串的最长回文子串是否在头尾_回文自动机入门

    缘起 回文自动机(Palindrome auto machine PAM,有些地方称之为回文树)是回文问题的大杀器~  本文使用一道很简单的题目入门这个精巧的数据结构. hdu 2163 Palind ...

  6. 回文串问题的克星——Palindrome Tree(回文树)/Palindrome Automaton(回文自动机)学习小记

    前言 最近B组有一道我不会的题,赶紧学习. 简介 我们知道,Manacher算法可以在 O(n) O ( n ) O(n)的时间内求出以每个位置为中心的最长回文串(虽然我昨天还不知道Manacher算 ...

  7. 「HDU6599 I Love Palindrome String」 - 回文自动机

    HDU 6599 I Love Palindrome String tags:回文自动机 题意 让你求有多少个 \([l,r]\) 满足 \(s[l,r]\) 和 \(s\left[l,\frac{l ...

  8. HDU-6599 I Love Palindrome String 杭电第二次多校赛(Manacher+回文自动机)

    HDU-6599 I Love Palindrome String 杭电第二次多校赛(Manacher+回文自动机) 我的博客:https://acmerszq.cn 原题链接:http://acm. ...

  9. HDU-6599 I Love Palindrome String(回文自动机+字符串hash)

    题目链接 题意:给定一个字符串\(|S|\le 3\times 10^5\) 对于每个 \(i\in [1,|S|]\) 求有多少子串\(s_ls_{l+1}\cdots s_r\)满足下面条件 \( ...

最新文章

  1. vector 容器 动态数组总结
  2. RESTful再理解
  3. 网站导航目录要该如何优化?
  4. 康奈尔ECE MEng项目拒信+1 哈哈哈
  5. boost::prior用法的测试程序
  6. 在工作迷惘的寒冬感受亲情的温暖。
  7. Spring注解配置工作原理源码解析
  8. java构造器_Java类加载的过程
  9. PAT乙级(1020 月饼)
  10. 【linux系统编程】远程登录工具ssh | 跨主机远程拷贝scp
  11. linux hal-get-property进程说明,Android HAL property_get() 函数用法
  12. Code Review
  13. flex4 权威指南 part01
  14. css3中3d旋转中rotatex,rotatey,rotatez的旋转正方向
  15. 系统分析师和系统架构设计师的主要区别是什么?
  16. Python的视频分析
  17. 【免费模版分享】任务管理移动端Axure原型模板
  18. 关于zip命令的使用问题
  19. Python零基础学习笔记(三十三)—— 窗体的控制
  20. 让my97 datepicker兼容ie9、ie10、ie11

热门文章

  1. Apollo创建项目
  2. AIO(Asynchronous IO)基本原理
  3. TCP/IP协议的SYN攻击
  4. Redis 安装启动
  5. jwt:token的解析
  6. 数据库-数据库的备份与恢复
  7. Spring Session官方介绍及spring框架学习方法
  8. list lt t gt java_将DataTable转换成Listlt;Tgt;实现思路及示例代码
  9. 学完java学swift_前言最近学完Swift之后一直没有机会实战,发现由于Swift发展历史原因,目前网上大部分的算法都是使用C、Java或其他语言实现的,几乎没有使用Swift实...
  10. 200813_C指针