Codeforces 932G Palindrome Partition - 回文树 - 动态规划
题目传送门
通往???的传送点
通往神秘地带的传送点
通往未知地带的传送点
题目大意
给定一个串$s$,要求将$s$划分为$t_{1}t_{2}\cdots t_{k}$,其中$2\mid k$,且$t_{i} = t_{k - i}$,问方案数。
直接做不太好做。虽然可以$O(n^{2})$进行动态规划。
考虑做一步转化:设$s' = s_{1}s_{n}s_{2}s_{n - 1}\cdots s_{n / 2}s_{n / 2 + 1}$。
然后它的一个偶回文划分可以和原来的划分一一对应。
于是可以$O(n^{2})$进行动态规划。然后完美TLE。
定理1 一个回文的后缀是回文串当且仅当它是原串的border。
根据回文串和border的定义容易证明。
引理1 (Weak Periodicity Lemma) 设$p$和$q$是$s$的周期,且$p + q \leqslant |s|$,则$(p, q)$也是$s$的周期
证明 不妨设$p < q, d = q - p$。
- 当$|s| - q\leqslant i \leqslant |s| - d$时,$s_{i} = s_{i - p} = s_{i - p + q} = s_{i + d}$
- 当$1\leqslant i < |s| - q$时,$s_{i} = s_{i + q} = s_{i + q - p} = s_{i + d}$。
然后根据辗转相除法能够得到$(p, q)$也是$s$的周期。因此定理得证。
引理2 字符串的所有长度不小于$|s| / 2$的所有border的长度构成等差数列。
证明 设$|s| - p (p\leqslant |s| / 2)$是$s$最长的$border$,另外某个border的长度是:$|s| - q (q\leqslant |s| / 2)$,那么能够推出$(p, q)$是$s$的周期,因此$|s| - (p, q)$也是字符串$s$的border。由$p$的最小性以及$(p, q)\leqslant p$可知$(p, q) = p$,即$p\mid q$。
(懒得画图了,直接截论文的图)
不难证明对于任意$q (q\leqslant |s| / 2)$,且$p\mid q$的后缀是字符串$s$的border。
推论 一个字符串的border可以被分为不超过$\left \lceil log_{2}n \right \rceil$段等差数列。
证明 设$2^{k}\leqslant n < 2^{k + 1}$,考虑以下几段的border:
$\begin{matrix}[2^{k}, n]\\ [2^{k - 1}, s^{k})\\ [2^{k - 2}, 2^{k - 1})\\ \vdots \\ [1, 2)\end{matrix}$
根据引理2可得长度属于每一段的border都是一个等差数列。
因此得证。
有了这个推论有什么用呢?
对于每一类border,每一次它被成为当前前缀的border意味着当前串的长度减去周期后,这些border还被发现了一次。
如上图,每次如果能够预处理出橙色部分,转移的时候只用补上没有计算的一项就好了.
用$f[i]$表示第$i$个前缀的偶回文划分的方案数。
用$g[i]$表示在回文树的状态$i$作为等差数列末项的时候等差border的动态规划的值的和。
建回文树的时候记一下dif和slink就可知道等差数列的差以及上一类等差数列的末项。
Code
/**
* Codeforces
* Problem#932G
* Accepted
* Time: 93ms
* Memory: 128200k
*/
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; const int alpha = ; typedef class TrieNode {
public:
int len, dif, g;
TrieNode *ch[alpha];
TrieNode *fail, *slink;
}TrieNode; typedef class PalindromeTree {
public:
int len;
TrieNode *pool;
TrieNode *top;
TrieNode *odd, *even;
TrieNode *last;
char *str; TrieNode* newnode(int len) {
top->len = len, top->dif = -, top->g = ;
memset(top->ch, , sizeof(top->ch));
top->fail = top->slink = NULL;
return top++;
} PalindromeTree() { }
PalindromeTree(int n) {
pool = new TrieNode[(n + )];
str = new char[(n + )];
top = pool, len = ;
odd = newnode(-), even = newnode();
odd->fail = odd, even->fail = odd;
odd->dif = even->dif = -, last = even, str[] = ;
} TrieNode* extend(TrieNode* p) {
while (str[len - p->len - ] != str[len]) p = p->fail;
return p;
} void append(char x) {
str[++len] = x;
int c = x - 'a';
last = extend(last);
if (!last->ch[c]) {
TrieNode* p = newnode(last->len + );
p->fail = extend(last->fail)->ch[c];
if (!p->fail)
p->fail = even;
last->ch[c] = p;
p->dif = p->len - p->fail->len; if (p->dif == p->fail->dif)
p->slink = p->fail->slink;
else
p->slink = p->fail;
}
last = last->ch[c];
}
}PalindromeTree; const int M = 1e9 + ; int n;
char bstr[], str[];
PalindromeTree pt;
int *f; inline void init() {
gets(bstr + );
n = strlen(bstr + );
for (int i = ; i <= n; i++) {
if (i & )
str[i] = bstr[(i + ) >> ];
else
str[i] = bstr[n - (i >> ) + ];
}
f = new int[(n + )];
memset(f, , sizeof(int) * (n + ));
} inline void solve() {
pt = PalindromeTree(n);
f[] = ;
for (int i = ; i <= n; i++) {
pt.append(str[i]);
for (TrieNode* p = pt.last; p && p->len > ; p = p->slink) {
p->g = f[i - p->slink->len - p->dif]; if (p->fail->dif == p->dif)
p->g = (p->g + p->fail->g) % M;
if (!(i & ))
f[i] = (f[i] + p->g) % M;
}
}
printf("%d", f[n]);
} int main() {
init();
solve();
return ;
}
Codeforces 932G Palindrome Partition - 回文树 - 动态规划的更多相关文章
- Codeforces 932G Palindrome Partition 回文树+DP
题意:给定一个串,把串分为偶数段 假设分为$s_1,s_2,s_3....s_k$ 求满足$ s_1=s_k,s_2=s_{ k-1 }... $的方案数模$10^9+7$ $|S|\leq 10^6 ...
- CF932G Palindrome Partition(回文自动机)
CF932G Palindrome Partition(回文自动机) Luogu 题解时间 首先将字符串 $ s[1...n] $ 变成 $ s[1]s[n]s[2]s[n-1]... $ 就变成了求 ...
- Palisection(Codeforces Beta Round #17E+回文树)
题目链接 传送门 题意 给你一个串串,问你有多少对回文串相交. 思路 由于正着做不太好算答案,那么我们考虑用总的回文对数减去不相交的回文对数. 而不相交的回文对数可以通过计算以\(i\)为右端点的回文 ...
- HDU 6599 I Love Palindrome String (回文树+hash)
题意 找如下子串的个数: (l,r)是回文串,并且(l,(l+r)/2)也是回文串 思路 本来写了个回文树+dfs+hash,由于用了map所以T了 后来发现既然该子串和该子串的前半部分都是回文串,所 ...
- 【CF932G】Palindrome Partition 回文自动机
[CF932G]Palindrome Partition 题意:给你一个字符串s,问你有多少种方式,可以将s分割成k个子串,设k个子串是$x_1x_2...x_k$,满足$x_1=x_k,x_2=x_ ...
- 2019牛客暑期多校训练营(第六场)Palindrome Mouse 回文树+dfs
题目传送门 题意:给出一个字符串,将字符串中所有的回文子串全部放入一个集合里,去重后.问这个集合里有几对<a,b>,使得a是b的子串. 思路:一开始想偏了,以为只要求每个回文串的回文后缀的 ...
- @codeforces - 932G@ Palindrome Partition
目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定一个字符串 s,求有多少种方案可将其划分成偶数个段 \(p_ ...
- Palindrome Partition CodeForces - 932G 回文树+DP+(回文后缀的等差性质)
题意: 给出一个长度为偶数的字符串S,要求把S分成k部分,其中k为任意偶数,设为a[1..k],且满足对于任意的i,有a[i]=a[k-i+1].问划分的方案数. n<=1000000 题解: ...
- 【CF932G】Palindrome Partition(回文树,动态规划)
[CF932G]Palindrome Partition(回文树,动态规划) 题面 CF 翻译: 给定一个串,把串分为偶数段 假设分为了\(s1,s2,s3....sk\) 求,满足\(s_1=s_k ...
随机推荐
- tensorflow 在windows下的安装
anaconda3 python3.5 tensorflow 在 windows下的安装 1.安装Anaconda 清华的镜像:https://mirrors.tuna.tsinghua.edu.cn ...
- Oracle 使用Dblink
DBLINK数据库链接是一个数据库中的模式对象,使您可以访问另一个数据库上的对象. dblink限定符允许您引用除本地数据库以外的数据库中的对象,如果省略了dblink,那么Oracle假定您指的是本 ...
- table中内容过长,table改变的问题
在看效果时发现在Chrome中的table已经不是原来设置的宽度了,而其他浏览器是好的,经过百度发现是单元格内容过多造成的,但这时候给td设置宽度已经不适用了,此时就要给table设置 table{t ...
- ssm项目中KindEditor的图片上传插件,浏览器兼容性问题
解决办法: 原因:使用@ResponseBody注解返回java对象,在浏览器中是Content-Type:application/json;charset=UTF-8 我们需要返回字符串(Strin ...
- css 子盒子上下居中 文字溢出省略号
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- laravel使用记录
引用外部文件方式参考地址:https://blog.csdn.net/Darry_Zhao/article/details/52689635 跟踪数据库执行语句 DB::enableQueryLog( ...
- [httpd][daily] 查看并修改httpd的最大fd打开个数limit
重要提示: 请直接阅读步骤(6),如果不生效,再回头阅读(1)-(5). 如题: 修改这个文件就行了:/etc/security/limits.conf 查看当前配置的方法: 1. 找到httpd的p ...
- Linux之grep的使用
基本介绍 Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹 配的行打印出来.grep全称是Global Regular Expression Print,表示全 ...
- 4、 LwIP协议栈规范翻译——流程模型
4.流程模型 协议实现的流程模型描述了系统被划分为不同的流程的方式.用于实现通信协议的一个流程模型是让每个协议作为一个独立的进程运行.有了这个模型,严格的协议分层被强制执行,并且协议之间的通信点必须严 ...
- 关于${pageContext.request.contextPath}的理解 (转载)
${pageContext.request.contextPath}是JSP取得绝对路径的方法,等价于<%=request.getContextPath()%> . 也就是取出部署的应用程 ...