CF932G Palindrome Partition(回文自动机)

Luogu

题解时间

首先将字符串 $ s[1...n] $ 变成 $ s[1]s[n]s[2]s[n-1]... $

就变成了求将字符串全部划分为偶回文串的方案数。

建回文树大力跳$ fail $ 直接 $ dp $ 的复杂度是十分优秀的 $ O ( n ^ {2} ) $。

优化不容易想到。

考虑字符串上第 $ j $ 位为结尾的所有回文子串,毫无疑问它们在树上是一条链。

但它有个更重要的性质。

其中所有长度 $ > j / 2 $ 的子串的 $ len $ 等差。

证明有点难,但这个结论可能对做过[WC2016]论战捆竹竿的人来说十分熟悉。

然后将等差段的dp值整合到一起,每次跳就是 $ O( log_{2} n ) $。

然后就可以做了。

#include<bits/stdc++.h>
using namespace std;
typedef long long lint;
struct pat{int x,y;pat(int x=0,int y=0):x(x),y(y){}bool operator<(const pat &p)const{return x==p.x?y<p.y:x<p.x;}};
template<typename TP>inline void read(TP &tar)
{
TP ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){ret=ret*10+(ch-'0');ch=getchar();}
tar=ret*f;
}
namespace RKK
{
const int N=1000011,mo=1000000007;
void doadd(int &a,int b){if((a+=b)>=mo) a-=mo;} int dlen[N],anc[N];
struct remilia{int tranc[26],len,fail;};
struct sakuya
{
remilia p[N];
int tcnt,fin;
void init()
{
tcnt=fin=1;
p[0].len=0,p[1].len=-1;
p[0].fail=p[1].fail=1;
anc[0]=1;
}
sakuya(){init();}
int match(char *s,int i,int px){return s[i-p[px].len-1]==s[i];}
void ins(char *s,int i)
{
int ch=s[i]-'a';
int npx,lpx,lpy;
lpx=fin;
while(!match(s,i,lpx)) lpx=p[lpx].fail;
if(!p[lpx].tranc[ch])
{
npx=++tcnt,p[npx].len=p[lpx].len+2;
lpy=p[lpx].fail;
while(!match(s,i,lpy)) lpy=p[lpy].fail;
p[npx].fail=p[lpy].tranc[ch];
p[lpx].tranc[ch]=npx;
dlen[npx]=p[npx].len-p[p[npx].fail].len;
anc[npx]=p[npx].fail;if(dlen[npx]==dlen[p[npx].fail]) anc[npx]=anc[p[npx].fail];
}
fin=p[lpx].tranc[ch];
}
}pam;
int n;char str[N],rts[N]; int dp[N],dg[N];
int main()
{
#ifdef RDEBUG
freopen("sample.in","r",stdin);
#endif
scanf("%s",str+1),n=strlen(str+1);
for(int i=1;i<=n>>1;i++) rts[(i<<1)-1]=str[i];
reverse(str+1,str+1+n);
for(int i=1;i<=n>>1;i++) rts[i<<1]=str[i];
dg[0]=1;
for(int i=1;i<=n;i++)
{
pam.ins(rts,i);for(int px=pam.fin;px;px=anc[px])
{
dp[px]=dg[i-pam.p[anc[px]].len-dlen[px]];
if(anc[px]!=pam.p[px].fail) doadd(dp[px],dp[pam.p[px].fail]);
if((i&1)==0) doadd(dg[i],dp[px]);
}
}
printf("%d\n",dg[n]);
return 0;
}
}
int main(){return RKK::main();}

最新文章

  1. Python之路第一课Day4--随堂笔记(迭代生成装饰器)
  2. 使用ASP.NET 4的自动启动特性,解决ASP.NET第一次访问速度慢问题
  3. Shell 编程基础之注意技巧
  4. UISegmentedControl(转)
  5. FSL安装
  6. 网易云课堂_程序设计入门-C语言_第六章:数组_2鞍点
  7. SQL Pretty Printer for SSMS 很不错的SQL格式化插件
  8. python添加post请求
  9. 物联网架构成长之路(17)-SpringCloud目前遇到的注意事项
  10. datetime模块的简单用法
  11. dev16 cxgrid 在DLL里报0地址错
  12. hive-内部表和外部表 对比
  13. firedac数据集和字符串之间相互转换
  14. 让手机连接到指定的WIFI网络,适用于之前已经连过的网络
  15. Solr优化案例分析
  16. Oracle下各个NLS相关参数取得方法
  17. 一维码EAN 8简介及其解码实现(zxing-cpp)
  18. 3.4 Templates -- Displaying A List of Items(展示一个集合)
  19. GCD vs NSOperation
  20. day 23 模块2

热门文章

  1. 基于双TMS320C6678 + XC7K420T的6U CPCI Express高速数据处理平台
  2. linux 运维工程师如何降低工作难度
  3. XXE外部实体注入漏洞总结
  4. NeurIPS 2017 | TernGrad: Ternary Gradients to Reduce Communication in Distributed Deep Learning
  5. java中的运算符介绍
  6. Oracle之PL/SQL Developer的下载与安装
  7. linux中docker容器安装vi命令详解
  8. 多个n维向量围成的n维体积的大小
  9. AcWing 325. 计算机
  10. SpringBoot进阶教程(七十三)整合elasticsearch