2019ICPC(沈阳) (回文自动机+Palindrome Series优化dp)
无从追溯的一道题目。。
题目大意:给出一个字符串 s,要求在 s 中选出3个互不相交的回文子串,求长度之和的最大值
题目分析:考虑 n * n 的 dp,dp[ i ][ k ] 为 s[ 1 : i ] 的前缀中,选出了 j 个回文子串的最大长度,转移的话也比较简单,先对字符串建立回文自动机,枚举以点 i 为结尾的所有回文子串,设枚举到的节点为 p:
- k == 1:dp[ i ][ 1 ] = len[ p ]
- 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)相关推荐
- CodeForces - 17E Palisection(回文自动机/Palindrome Series优化dp)
题目链接:点击查看 题目大意:给出一个长度为 n 的字符串,问有多少 相交的回文子串对数 题目分析:背 PAM 模板的时候突然发现了一道模板题,于是顺手写了..正难则反,可以先求出有多少个互不相交的回 ...
- CodeForces - 906E Reverses(回文自动机+Palindrome Series优化dp)
题目链接:点击查看 题目大意:给出两个字符串 s 和 t,每次可以在字符串 s 中选择数个不相交的字串进行反转,问最少需要反转多少次,可以使得字符串 s 和 t 相等,输出最小反转次数以及方案 题目分 ...
- CodeForces - 932G Palindrome Partition(回文自动机+Palindrome Series优化dp)
题目链接:点击查看 题目大意:给出一个长度为偶数的字符串,问将其分割成 k 个子串记为 a[ 1 ] , a[ 2 ] ... a[ k ] ,且满足 a[ i ] == a[ k - i + 1 ] ...
- SPOJ - IITKWPCE Let us play with strings(回文自动机+Palindrome Series优化dp)
题目链接:点击查看 题目大意:给出一个长度为 n 的字符串,问最少拆分成多少个连续的子串,使得每个子串都是一个回文串 题目分析:dp[ i ] 代表 s[ 1 : i ] 的前缀最少可以拆分成多少个连 ...
- 怎么判断一个字符串的最长回文子串是否在头尾_回文自动机入门
缘起 回文自动机(Palindrome auto machine PAM,有些地方称之为回文树)是回文问题的大杀器~ 本文使用一道很简单的题目入门这个精巧的数据结构. hdu 2163 Palind ...
- 回文串问题的克星——Palindrome Tree(回文树)/Palindrome Automaton(回文自动机)学习小记
前言 最近B组有一道我不会的题,赶紧学习. 简介 我们知道,Manacher算法可以在 O(n) O ( n ) O(n)的时间内求出以每个位置为中心的最长回文串(虽然我昨天还不知道Manacher算 ...
- 「HDU6599 I Love Palindrome String」 - 回文自动机
HDU 6599 I Love Palindrome String tags:回文自动机 题意 让你求有多少个 \([l,r]\) 满足 \(s[l,r]\) 和 \(s\left[l,\frac{l ...
- HDU-6599 I Love Palindrome String 杭电第二次多校赛(Manacher+回文自动机)
HDU-6599 I Love Palindrome String 杭电第二次多校赛(Manacher+回文自动机) 我的博客:https://acmerszq.cn 原题链接:http://acm. ...
- HDU-6599 I Love Palindrome String(回文自动机+字符串hash)
题目链接 题意:给定一个字符串\(|S|\le 3\times 10^5\) 对于每个 \(i\in [1,|S|]\) 求有多少子串\(s_ls_{l+1}\cdots s_r\)满足下面条件 \( ...
最新文章
- vector 容器 动态数组总结
- RESTful再理解
- 网站导航目录要该如何优化?
- 康奈尔ECE MEng项目拒信+1 哈哈哈
- boost::prior用法的测试程序
- 在工作迷惘的寒冬感受亲情的温暖。
- Spring注解配置工作原理源码解析
- java构造器_Java类加载的过程
- PAT乙级(1020 月饼)
- 【linux系统编程】远程登录工具ssh | 跨主机远程拷贝scp
- linux hal-get-property进程说明,Android HAL property_get() 函数用法
- Code Review
- flex4 权威指南 part01
- css3中3d旋转中rotatex,rotatey,rotatez的旋转正方向
- 系统分析师和系统架构设计师的主要区别是什么?
- Python的视频分析
- 【免费模版分享】任务管理移动端Axure原型模板
- 关于zip命令的使用问题
- Python零基础学习笔记(三十三)—— 窗体的控制
- 让my97 datepicker兼容ie9、ie10、ie11
热门文章
- Apollo创建项目
- AIO(Asynchronous IO)基本原理
- TCP/IP协议的SYN攻击
- Redis 安装启动
- jwt:token的解析
- 数据库-数据库的备份与恢复
- Spring Session官方介绍及spring框架学习方法
- list lt t gt java_将DataTable转换成Listlt;Tgt;实现思路及示例代码
- 学完java学swift_前言最近学完Swift之后一直没有机会实战,发现由于Swift发展历史原因,目前网上大部分的算法都是使用C、Java或其他语言实现的,几乎没有使用Swift实...
- 200813_C指针