题目传送门

  通往???的传送点

  通往神秘地带的传送点

  通往未知地带的传送点

题目大意

  给定一个串$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 - 回文树 - 动态规划的更多相关文章

  1. 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 ...

  2. CF932G Palindrome Partition(回文自动机)

    CF932G Palindrome Partition(回文自动机) Luogu 题解时间 首先将字符串 $ s[1...n] $ 变成 $ s[1]s[n]s[2]s[n-1]... $ 就变成了求 ...

  3. Palisection(Codeforces Beta Round #17E+回文树)

    题目链接 传送门 题意 给你一个串串,问你有多少对回文串相交. 思路 由于正着做不太好算答案,那么我们考虑用总的回文对数减去不相交的回文对数. 而不相交的回文对数可以通过计算以\(i\)为右端点的回文 ...

  4. HDU 6599 I Love Palindrome String (回文树+hash)

    题意 找如下子串的个数: (l,r)是回文串,并且(l,(l+r)/2)也是回文串 思路 本来写了个回文树+dfs+hash,由于用了map所以T了 后来发现既然该子串和该子串的前半部分都是回文串,所 ...

  5. 【CF932G】Palindrome Partition 回文自动机

    [CF932G]Palindrome Partition 题意:给你一个字符串s,问你有多少种方式,可以将s分割成k个子串,设k个子串是$x_1x_2...x_k$,满足$x_1=x_k,x_2=x_ ...

  6. 2019牛客暑期多校训练营(第六场)Palindrome Mouse 回文树+dfs

    题目传送门 题意:给出一个字符串,将字符串中所有的回文子串全部放入一个集合里,去重后.问这个集合里有几对<a,b>,使得a是b的子串. 思路:一开始想偏了,以为只要求每个回文串的回文后缀的 ...

  7. @codeforces - 932G@ Palindrome Partition

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定一个字符串 s,求有多少种方案可将其划分成偶数个段 \(p_ ...

  8. Palindrome Partition CodeForces - 932G 回文树+DP+(回文后缀的等差性质)

    题意: 给出一个长度为偶数的字符串S,要求把S分成k部分,其中k为任意偶数,设为a[1..k],且满足对于任意的i,有a[i]=a[k-i+1].问划分的方案数. n<=1000000 题解: ...

  9. 【CF932G】Palindrome Partition(回文树,动态规划)

    [CF932G]Palindrome Partition(回文树,动态规划) 题面 CF 翻译: 给定一个串,把串分为偶数段 假设分为了\(s1,s2,s3....sk\) 求,满足\(s_1=s_k ...

随机推荐

  1. selenium 操作过程中,元素标红高亮的两种实现方式

    在使用selenium时,动作元素标红高亮,在定位问题时相当好用,有以下二种方法可以实现 一.使用js将元素属性修改 这也是网上大部分的实现方式,但有时候会有点小问题,代码如下: 只写其实某一段函数 ...

  2. mui 事件管理及自定义事件详解

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name ...

  3. 时间选择器(timepicker)

    可以使用Slider拖动选择,也可以使用timespinner改变时间,或者手工填写. 自动判断位置 效果: 源码: <!DOCTYPE html> <html xmlns=&quo ...

  4. iOS 弹出菜单UIMenuController的基本使用

    UIMenuController,弹出菜单@implementation DragView{    CGPoint startLocation;    CGFloat rotation;}-(inst ...

  5. ES6中Set 和 Map用法

    JS中Set与Map用法 一.Set 1.基本用法 ES6 提供了新的数据结构 Set.它类似于数组,但是成员的值都是唯一的,没有重复的值. Set 本身是一个构造函数,用来生成 Set 数据结构. ...

  6. Windows渗透利器之Pentest BOX使用详解(一)

    内容概览:                                     知识科普                                    优缺点总结 功能参数详解翻译: 控制 ...

  7. nessus无法访问https://localhost:8834/#/,解决方法。

    之前没弄明白为啥经常访问不了https://localhost:8834/#/,后面才发现是服务关闭了. 首先netstat -an 查看8834是否开启, 直接运行一下nessus目录下的nessu ...

  8. 《Mysql 分区分表》

    一:分区/分表 为了什么? - 当MySQL单表的数据量过大时,数据库的访问速度会下降,需要处理大量数据,所以需要把数据分散存储. - 常用 "水平" 切分 二:MySQL常见的水 ...

  9. intellij idea 的全局搜索快捷键方法

    1.Ctrl+N按名字搜索类 相当于eclipse的ctrl+shift+R,输入类名可以定位到这个类文件,就像idea在其它的搜索部分的表现一样,搜索类名也能对你所要搜索的内容多个部分进行匹配,而且 ...

  10. slf4j日志使用

    scala中 trait LogSupport { protected val log = LoggerFactory.getLogger(this.getClass) } 需要要到的类 extend ...