题解 CF932G【Palindrome Partition】
题意
给出字符串 $A$ ,求 $A=A_1A_2A_3...A_k$ 的划分满足 $2|k$ 且 $\forall i\in[1,k],A_i=A_{k-i+1}$,对 $10^9+7$ 取模。
$|A|\le 10^6$.
思路
回文划分的模板题,我觉得 $\text{zhylj}$ 的题解写得很好,我就简述一下吧。
我们知道,字符串的 $\text{border}$ 集合可以划分为 $O(\log n)$ 个等差数列。
考虑一个回文串的回文后缀:
设 $t=s_{k,...n}$,若 $k,t\text{ is palindromic}$,则 $t\text{ is a border of } k$。
证:
因为 $k\text{ is palindromic}$,所以 $s_i=s_{|s|-i+1}$;
因为 $t\text{ is palindromic}$,所以$s_i=s_{|s|-i+1}=s_{|s|-(|t|-i+1)+1}=s_{|s|-|t|+1}$;
所以 $t\text{ is a border of } k$。
即得到回文串的回文后缀集合可以划分为 $O(\log n)$ 个等差数列。
在 $\text{PAM}$ 上,记 $diff_x=len_x-len_{fail_x}$,$slink_x$ 表示 $\text{Fail}$ 树上 $x$ 点祖先中离 $x$ 最近的满足 $diff_{a}\ne diff_x$ 的 $a$。
容易发现,在 $x\to slink_x$ 的路径中,$len_x-len_{fail_x}$ 恒为定值,即在跳一条等差数列,由上面的结论得,$x$ 最多能跳 $O(\log n)$ 次就会达到根节点。
首先考虑给出字符串 $A$ ,求 $A=A_1A_2A_3...A_k$ 的划分数满足 $\forall i\in[1,k],A_i\text{ is palindromic}$ 应该怎么做。
我们考虑一个 $\text{dp}$,设 $dp_i$ 表示 $i$ 前缀的答案,则有一个显然的转移方程:
$$dp_i=\sum_{j,s_{j+1,...,i\text{ is palindromic}}}dp_j$$ 如果枚举 $j$ 只能做到 $O(n^2)$ 的时间复杂度。
由于回文串的回文后缀又是 $\text{border}$,所以等差数列中的后缀都平移了公差 $diff_x$。
那么 $dp$ 就成为了 $dp_{i-len_{slink_x}-diff_x}$,于是我们可以记录 $f_x$ 表示 $x\to slink_x$ 中链上回文子串最后一次出现对应的 $dp$ 值,我们可以简单地将 $f_{fail_x}$ 转移至 $f_x$,于是在加入节点时我们就可以跳 $x\to slink_x$,更新 $f_x$ 即可。
然后回到本题,我们可以考虑构造 $B=a_1a_na_2a_{n-1}...$,问题转化为对 $B$ 的偶回文子串划分。
那么只在 $2|i$ 时做出贡献即可。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//by cyffff
}
const int N=1e6+10,mod=1e9+7;
int n;
int dp[N],f[N];
char str[N],inp[N];
struct Palindromic_Tree{
struct node{
int ch[26];
int fail,len,diff,slink;
}a[N];
int last,siz;
inline void init(){
siz=1,last=0;
a[0].fail=1,a[1].fail=0;
a[0].len=0,a[1].len=-1;
}
inline int getfail(int p,int x){
while(str[x]!=str[x-a[p].len-1])
p=a[p].fail;
return p;
}
inline void insert(char ch,int x){
int p=getfail(last,x);
int w=ch-'a';
if(!a[p].ch[w]){
int cur=++siz;
a[cur].len=a[p].len+2;
int tmp=getfail(a[p].fail,x);
a[cur].fail=a[tmp].ch[w];
a[p].ch[w]=cur;
a[cur].diff=a[cur].len-a[a[cur].fail].len;
a[cur].slink=(a[cur].diff==a[a[cur].fail].diff)?a[a[cur].fail].slink:a[cur].fail;
}
last=a[p].ch[w];
}
inline void calc(){
init();
n=readstr(inp);
if(n&1){
write(0);
return ;
}
for(int i=1;i<=n;i+=2) str[i]=inp[i+1>>1];
reverse(inp+1,inp+n+1);
for(int i=2;i<=n;i+=2) str[i]=inp[i+1>>1];
dp[0]=1;
str[0]='\n';
for(int i=1;i<=n;i++){
insert(str[i],i);
for(int j=last;j;j=a[j].slink){
f[j]=dp[i-a[a[j].slink].len-a[j].diff];
if(a[j].slink!=a[j].fail){
f[j]=(f[j]+f[a[j].fail])%mod;
}
if(i%2==0)
dp[i]=(dp[i]+f[j])%mod;
}
}
write(dp[n]);
}
}PAM;
int main(){
PAM.calc();
flush();
return 0;
}
居然跑到了洛谷 rk1
再见 qwq~

浙公网安备 33010602011771号