【CF932G】Palindrome Partition 回文自动机
【CF932G】Palindrome Partition
题意:给你一个字符串s,问你有多少种方式,可以将s分割成k个子串,设k个子串是$x_1x_2...x_k$,满足$x_1=x_k,x_2=x_{k-1}...x_i=x{k-i+1}$。
$|s|\le 10^6$
题解:设字符串的长度为n,考虑字符串$T=s_1s_ns_2s_{n-1}...$。问题就转化成了:求将原串划分成若干个长度为偶数的回文子串的方案数。
首先我们有一种暴力的想法,设f[i]表示将前i个字符分成若干个回文子串的方案数,先跑回文自动机或Manacher得到所有$O(n^2)$个回文串。然后有转移方程$f[i]=\sum f[j] [s(i,j)是回文串]$,特别地,对于奇数的i,f[i]=0。
但是观察发现,如果$s(1,i)=A+DD..DT$,其中$T,DT,DDT...$都是回文串,那么显然有转移$f[i]=f[i-|T|]+f[i-|DT|]+...$,而注意到对于$i-|T|$这个位置,也存在转移$f[i-|T|]=f[i-|DT|]+f[i-|DDT|]+...$。也就是说,f[i]和f[i-|T|]有相当多的转移是相同的!我们能不能利用这个性质来优化我们的算法呢?
接着,对于回文自动机上的每个节点,我们定义$diff[i]=len[i]-len[fail[i]]$,$sf[i]$表示i沿着fail指针往上走,走到的第一个$diff$与i不同的祖先。我们是不是可以把fail链上连续的diff相同的点放在一起呢?当然是可以的,有如下结论:
引理1:从一个点沿着sf指针向上走,最多走log步就能到达根节点。
证明很复杂,不过有一种比较容易的感性理解方法:就是当diff<len/2的时候,diff一定不变;diff>len/2的时候,diff又一定改变(画画图能看出来)。所以每次len缩小一半,长度就是log的了。
为了保证正确性,我们还需要证明一个东西:
引理2:设j是i对应的节点在fail树上的一个祖先,且diff[j]!=diff[fail[j]],则在所有以i-diff[j]结尾的回文串中,长度最长的为len[j]-diff[j]。
这个也不太会证,画画图吧~
不过引理2保证了我们直接调用f[i-diff[j]]时不会统计到无关的信息。现在我们可以将diff相同的部分放到一起处理了,只需要维护一个类似于前缀和的东西,到时候暴力沿着sf向上走统计答案即可。具体可见代码。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int P=1000000007;
const int maxn=1000010;
inline void upd(int &x,const int &y) {x+=y; if(x>=P) x-=P;}
int f[maxn],g[maxn];
int n,last,tot;
int ch[maxn][26],fa[maxn],len[maxn],diff[maxn],sf[maxn];
char ss[maxn],str[maxn];
inline void extend(int x)
{
int p=last,c=str[x]-'a';
for(;str[x-len[p]-1]!=str[x];p=fa[p]);
if(!ch[p][c])
{
int np=++tot,q=fa[p]; len[np]=len[p]+2;
for(;str[x-len[q]-1]!=str[x];q=fa[q]);
fa[np]=ch[q][c];
ch[p][c]=np;
diff[np]=len[np]-len[fa[np]];
if(diff[np]==diff[fa[np]]) sf[np]=sf[fa[np]];
else sf[np]=fa[np];
}
last=ch[p][c];
}
int main()
{
scanf("%s",ss+1),n=strlen(ss+1);
int i,p;
for(i=1;i+i<=n;i++) str[i*2-1]=ss[i],str[i*2]=ss[n+1-i];
tot=fa[0]=1,len[1]=-1;
f[0]=1;
for(i=1;i<=n;i++)
{
extend(i);
p=last;
for(p=last;p>1;p=sf[p])
{
g[p]=f[i-len[sf[p]]-diff[p]];
if(diff[p]==diff[fa[p]]) upd(g[p],g[fa[p]]);
upd(f[i],g[p]);
}
if(i&1) f[i]=0;
}
printf("%d",f[n]);
return 0;
}
【CF932G】Palindrome Partition 回文自动机的更多相关文章
- CF932G Palindrome Partition(回文自动机)
CF932G Palindrome Partition(回文自动机) Luogu 题解时间 首先将字符串 $ s[1...n] $ 变成 $ s[1]s[n]s[2]s[n-1]... $ 就变成了求 ...
- [2019杭电多校第二场][hdu6599]I Love Palindrome String(回文自动机&&hash)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6599 题目大意为求字符串S有多少个子串S[l,r]满足回文串的定义,并且S[l,(l+r)/2]也满足 ...
- 2019牛客暑期多校训练营(第六场)C - Palindrome Mouse (回文自动机)
https://ac.nowcoder.com/acm/contest/886/C 题意: 给出一个串A , 集合S里面为A串的回文字串 , 现在在集合S里面找出多少对(a,b),b为a的字串 分析: ...
- hdu多校第二场1009 (hdu6599) I Love Palindrome String 回文自动机/字符串hash
题意: 找出这样的回文子串的个数:它本身是一个回文串,它的前一半也是一个回文串 输出格式要求输出l个数字,分别代表长度为1~l的这样的回文串的个数 题解: (回文自动机和回文树是一个东西) 首先用回文 ...
- Codeforces 932G Palindrome Partition - 回文树 - 动态规划
题目传送门 通往???的传送点 通往神秘地带的传送点 通往未知地带的传送点 题目大意 给定一个串$s$,要求将$s$划分为$t_{1}t_{2}\cdots t_{k}$,其中$2\mid k$,且$ ...
- 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 ...
- 2019 Multi-University Training Contest 2 I.I Love Palindrome String(回文自动机+字符串hash)
Problem Description You are given a string S=s1s2..s|S| containing only lowercase English letters. F ...
- WHU 583 Palindrome ( 回文自动机 && 本质不同的回文串的个数 )
题目链接 题意 : 给你一个串.要你将其划分成两个串.使得左边的串的本质不同回文子串的个数是右边串的两倍.对于每一个这样子的划分.其对答案的贡献就是左边串的长度.现在要你找出所有这样子的划分.并将贡献 ...
- HDU-6599 I Love Palindrome String(回文自动机+字符串hash)
题目链接 题意:给定一个字符串\(|S|\le 3\times 10^5\) 对于每个 \(i\in [1,|S|]\) 求有多少子串\(s_ls_{l+1}\cdots s_r\)满足下面条件 \( ...
随机推荐
- wamp 配置虚拟主机
1.首先打开apache的配置文件httpd.conf,并去掉#Include conf/extra/httpd-vhosts.conf前面的#,启用虚拟主机功能 2.先把localhost配置好,免 ...
- UNIX环境编程学习笔记(23)——信号处理初步学习
lienhua342014-10-29 1 信号的概念 维基百科中关于信号的描述是这样的: 在计算机科学中,信号(英语:Signals)是 Unix.类 Unix 以及其他 POSIX 兼容的操作系统 ...
- 在Android中,px,dp,dip,sp的不同之处
最近在学习Android开发,一直没有弄清楚px,dp,dip,sp的区别.今天正好有时间,就花时间研究了一下. 众所周知,Android厂商非常多,各种尺寸的Android手机 ...
- QT运行出错:QObject::connect: Parentheses expected以及QObject::connect: No such slot ***
我在QGraphicsScene子类中添加了item的弹出菜单,并连接Action到槽函数,结果槽函数不起作用,输出:QObject::connect: No such slot *** C++ C ...
- Sublime的插件Color Highlighter的安装方法
ColorHighlighter是一个显示选中颜色代码的视觉颜色的插件.如果您选择“# fff“,它将向您展示白色.ColorHighlighter支持所有CSS颜色格式,如Hex,RGB,HSL,H ...
- Oracle创建directory
Oracle创建directory 一般创建directory都是为了用数据泵导入/导出数据用,其实directory还有很多别的用处,本文不做阐述 1.新建directory的语法 CREA ...
- git branch 命令
1.git init 该命令执行之后并没有创建branch 2.git add 添加文件,这时branch 也还没生成.git branch name也没用 3.git commit 提交到git r ...
- 给你的 Golang 程序添加 GUI (使用 Electron )
https://studygolang.com/articles/12065?fr=sidebar https://www.jianshu.com/p/a3be0d206d4c 另一种思路 推荐方式 ...
- 自动构建工具Grunt
摘要: 大部分项目在部署之前都需要做的就是js.css文件的压缩.合并,以及一些文件的错误检查,甚至是将LESS文件转换成css文件,coffeescript文件转化成js文件等等.但是项目开发是分迭 ...
- Unity 协程使用指南
0x00 前言 在使用Unity的过程中,对协程仅仅知道怎样使用,但并不知道协程的内部机理,对于自己不清楚的部分就像一块大石压力心里.让自己感觉到担忧和不适. 这篇文章一探到底,彻底揭开协程的面纱,让 ...