[Str记录]CF932G Palindrome Partition
command_block · · 个人记录
题意 : 给定串
求满足
我们按照
可以在
根据 结论① ,
对于一个等差序列,如果中间某两项不满足 结论② 则将其强行断开,不难发现,等差数列的个数仍然是
这样,每条等差序列相邻两个串之间都满足 结论② ,便于我们确定匹配位置。
对各个等差序列分别转移。
如图,绿红蓝为同一等差序列中的三个串,绿色虚线表示绿色串上一次出现的位置,蓝色虚线同理。
设当前处理
(该等差链中)能转移到
红色串的出现位置我们还不能确知。但能够肯定的是,其一定不会给
不难发现,
需要给每条回文链记录上一次转移的贡献,注意这不是链剖分,各个等差序列可能重叠,所以需要把这个信息记录在等差序列的最深处。
具体如何处理等差链请见代码。
复杂度
#include<algorithm>
#include<cstring>
#include<cstdio>
#define MaxN 1000500
using namespace std;
const int mod=1000000007;
struct Node
{int t[26],len,f,tf,d,s;}a[MaxN];
int tn,las;
void linkd(int u)
{
int fa=a[u].f;
a[u].d=a[u].len-a[fa].len;
a[u].tf=(a[u].d==a[fa].d&&a[u].d*2<=a[u].len) ? a[fa].tf : u;
}
void ins(int k,int c,char *str)
{
int p=las;
while(str[k-a[p].len-1]!=c)p=a[p].f;
if (!a[p].t[c]){
int np=las=++tn,v;
for (v=a[p].f;str[k-a[v].len-1]!=c;v=a[v].f);
if (!a[v].t[c])a[np].f=2;
else a[np].f=a[v].t[c];
a[a[p].t[c]=np].len=a[p].len+2;
linkd(np);
}else las=a[p].t[c];
}
int f[MaxN];
void dp(int k)
{
for (int p=las;p>2;p=a[a[p].tf].f){
int tl=a[a[p].tf].len;
a[p].s=f[k-tl];
if (a[p].tf!=p)a[p].s=(a[a[p].f].s+a[p].s)%mod;
if (!(k&1))f[k]=(f[k]+a[p].s)%mod;
}
}
void Init()
{a[1].f=a[2].f=1;a[1].len=-1;las=tn=2;}
int n;
char s[MaxN],s2[MaxN];
int main()
{
scanf("%s",s2+1);
n=strlen(s2+1);
if (n&1){puts("0");return 0;}
for (int i=1;i+i<=n;i++){
s[i*2-1]=s2[n-i+1];
s[i*2]=s2[i];
}s[0]=-1;f[0]=1;Init();
for (int i=1;i<=n;i++){
ins(i,s[i]-='a',s);
dp(i);
}printf("%d",f[n]);
return 0;
}