CF932G Palindrome Partition(回文自动机)
2024-09-08 11:10:20
CF932G Palindrome Partition(回文自动机)
题解时间
首先将字符串 $ 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();}
最新文章
- Python之路第一课Day4--随堂笔记(迭代生成装饰器)
- 使用ASP.NET 4的自动启动特性,解决ASP.NET第一次访问速度慢问题
- Shell 编程基础之注意技巧
- UISegmentedControl(转)
- FSL安装
- 网易云课堂_程序设计入门-C语言_第六章:数组_2鞍点
- SQL Pretty Printer for SSMS 很不错的SQL格式化插件
- python添加post请求
- 物联网架构成长之路(17)-SpringCloud目前遇到的注意事项
- datetime模块的简单用法
- dev16 cxgrid 在DLL里报0地址错
- hive-内部表和外部表 对比
- firedac数据集和字符串之间相互转换
- 让手机连接到指定的WIFI网络,适用于之前已经连过的网络
- Solr优化案例分析
- Oracle下各个NLS相关参数取得方法
- 一维码EAN 8简介及其解码实现(zxing-cpp)
- 3.4 Templates -- Displaying A List of Items(展示一个集合)
- GCD vs NSOperation
- day 23 模块2
热门文章
- 基于双TMS320C6678 + XC7K420T的6U CPCI Express高速数据处理平台
- linux 运维工程师如何降低工作难度
- XXE外部实体注入漏洞总结
- NeurIPS 2017 | TernGrad: Ternary Gradients to Reduce Communication in Distributed Deep Learning
- java中的运算符介绍
- Oracle之PL/SQL Developer的下载与安装
- linux中docker容器安装vi命令详解
- 多个n维向量围成的n维体积的大小
- AcWing 325. 计算机
- SpringBoot进阶教程(七十三)整合elasticsearch