首先正难则反,想到答案即为满足第一条要求的回文子序列数量,减去回文子串数量。回文子串数量 \(hash+\) 二分即可,考虑前半部分。

假如我们将一个回文子序列一层层剥开,就会发现它其实是由多个相同的字母对拼成的。那么容易想到把字母 \(a\) 和字母 \(b\) 的贡献分开计算。那第一条要求就可以转化为所有字母对中心相同,用 \(FFT\) 计算 \(c_k\),表示所有 \(i+j=k\) 的字母对数量即可。

时间复杂度 \(O(n\log n)\)。

#include<bits/stdc++.h>
#define int long long
#define ull unsigned int
using namespace std;
const ull q=1145141;
const int N=4e5+5,p=1e9+7;
const double pi=acos(-1);
namespace FFT{
int rev[N],mx,k;
struct comn{double a,b;};
struct dft{comn fg[N];};
comn operator+(comn &x,comn &y){
return {x.a+y.a,x.b+y.b};
}comn operator-(comn &x,comn &y){
return {x.a-y.a,x.b-y.b};
}comn operator*(comn &x,comn &y){
return {x.a*y.a-x.b*y.b,x.a*y.b+x.b*y.a};
}void operator+=(comn &x,comn &y){x=x+y;}
void operator-=(comn &x,comn &y){x=x-y;}
void operator*=(comn &x,comn &y){x=x*y;}
void operator+=(dft &x,dft &y){
for(int i=0;i<mx;i++) x.fg[i]+=y.fg[i];
}void operator-=(dft &x,dft &y){
for(int i=0;i<mx;i++) x.fg[i]-=y.fg[i];
}void init(int n){
mx=1,k=0,rev[0]=0;
while(mx<=n) mx*=2,k++;
for(int i=0;i<mx;i++)
rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));
}void fft(dft &a,int fl){
for(int i=0;i<mx;i++)
if(i<rev[i]) swap(a.fg[i],a.fg[rev[i]]);
comn o={cos(pi),fl*sin(pi)},w={1,0};
for(int i=1;i<mx;i*=2,o={cos(pi/i),fl*sin(pi/i)})
for(int j=0;j<mx;j+=i*2,w={1,0})
for(int l=j;l<j+i;l++){
comn x=a.fg[l],y=w*a.fg[l+i];
a.fg[l]+=y,a.fg[l+i]=x-y,w*=o;
}
}
}using namespace FFT;
int n,ans;string s;dft t[2];
ull hsh1[N],hsh2[N],qp[N];
int qpow(int x,int y){
int re=1;
while(y){
if(y&1) re=re*x%p;
x=x*x%p,y>>=1;
}return re;
}ull hs1(int l,int r){
return hsh1[l]-hsh1[r]*qp[l-r];
}ull hs2(int l,int r){
return hsh2[l]-hsh2[r]*qp[r-l];
}signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>s,n=s.size(),qp[0]=1;
s=" "+s,init(2*n);
for(int i=1;i<=n;i++){
t[s[i]-'a'].fg[i].a++,qp[i]=qp[i-1]*q;
hsh1[i]=hsh1[i-1]*q+s[i]-'a';
}for(int i=n;i;i--)
hsh2[i]=hsh2[i+1]*q+s[i]-'a';
fft(t[0],1),fft(t[1],1);
for(int i=0;i<mx;i++){
t[0].fg[i]*=t[0].fg[i];
t[1].fg[i]*=t[1].fg[i];
}fft(t[0],-1),fft(t[1],-1);
for(int i=2;i<=2*n;i++){
int sum=((t[0].fg[i].a+t[1].fg[i].a)/mx+0.5);
ans+=qpow(2,sum/2-(i&1)+1)-1;
}for(int i=1;i<=n;i++){
int l=1,sum=0;
int r=min(i,n-i+1);
while(l<=r){
int mid=(l+r)/2;
if(hs1(i,i-mid)==hs2(i,i+mid))
l=mid+1,sum=mid;else r=mid-1;
}ans-=sum;
}for(int i=1;i<n;i++){
int l=1,sum=0;
int r=min(i,n-i);
while(l<=r){
int mid=(l+r)/2;
if(hs1(i,i-mid)==hs2(i+1,i+mid+1))
l=mid+1,sum=mid;else r=mid-1;
}ans-=sum;
}cout<<(ans%p+p)%p;
return 0;
}

[BZOJ3160] 万径人踪灭 题解的更多相关文章

  1. [bzoj3160]万径人踪灭_FFT_Manacher

    万径人踪灭 bzoj-3160 题目大意:给定一个ab串.求所有的子序列满足:位置和字符都关于某条对称轴对称而且不连续. 注释:$1\le n\le 10^5$. 想法: 看了大爷的题解,OrzOrz ...

  2. BZOJ3160 万径人踪灭 字符串 多项式 Manachar FFT

    原文链接http://www.cnblogs.com/zhouzhendong/p/8810140.html 题目传送门 - BZOJ3160 题意 给你一个只含$a,b$的字符串,让你选择一个子序列 ...

  3. BZOJ3160万径人踪灭

    Description Input & Output & Sample Input & Sample Output HINT 题解: 题意即求不连续但间隔长度对称的回文串个数. ...

  4. BZOJ3160 万径人踪灭(FFT+manacher)

    容易想到先统计回文串数量,这样就去掉了不连续的限制,变为统计回文序列数量. 显然以某个位置为对称轴的回文序列数量就是2其两边(包括自身)对称相等的位置数量-1.对称有啥性质?位置和相等.这不就是卷积嘛 ...

  5. BZOJ3160 万径人踪灭 【fft + manacher】

    题解 此题略神QAQ orz po神牛 由题我们知道我们要求出: 回文子序列数 - 连续回文子串数 我们记为ans1和ans2 ans2可以用马拉车轻松解出,这里就不赘述了 问题是ans1 我们设\( ...

  6. BZOJ3160: 万径人踪灭

    设a[i]=bool(s[i]=='a'),b[i]=bool(s[i]=='b'),考虑a和a.b和b的卷积,由于卷积是对称的,就可以统计出不连续回文子串个数了.可能说得比较简略.再用manache ...

  7. bzoj千题计划302:bzoj3160: 万径人踪灭

    https://www.lydsy.com/JudgeOnline/problem.php?id=3160 不连续的回文串数量=所有的回文序列数量-连续的回文子串 连续的回文子串: manacher ...

  8. BZOJ3160:万径人踪灭(FFT,Manacher)

    Solution $ans=$回文子序列$-$回文子串的数目. 后者可以用$manacher$直接求. 前者设$f[i]$表示以$i$为中心的对称的字母对数. 那么回文子序列的数量也就是$\sum_{ ...

  9. BZOJ3160: 万径人踪灭(FFT,回文自动机)

    BZOJ传送门: 解题思路: FFT在处理卷积时可以将自己与自己卷,在某一种字母上标1其他标0,做字符集次就好了. (回文就是直接对称可以联系偶函数定义理解,根据这个性质就可以将字符串反向实现字符串匹 ...

  10. $FFT/NTT/FWT$题单&简要题解

    打算写一个多项式总结. 虽然自己菜得太真实了. 好像四级标题太小了,下次写博客的时候再考虑一下. 模板 \(FFT\)模板 #include <iostream> #include < ...

随机推荐

  1. echarts 的使用

    <template> // option 通过id行绑定     <div id="myRangChart" style="width: 100%;he ...

  2. 借助AI助手快速解析LlamaIndex的Workflow设计与Java迁移

    在前面的讨论中,我们通过AI助手快速浏览并分析了LlamaIndex的核心源码及其可视化部分.在上次的工作中,我们已基本完成了使用Java版本实现的可视化部分,尽管在工作流(workflow)的分析上 ...

  3. Vite项目无法通过IP+端口的方式访问开发服务

    前情 最近要新开一个项目,技术栈由自己安排,于是就想到使用vue3+vite来做,体验一把新技术栈 坑位 vite开发体验极佳,但是在项目完成的时候,想通过本地服务提前发给产品确认UI.交互等细节的时 ...

  4. 小程序 + node koa2 session存储验证码碰到最大的坑,(喜极而泣 /狗头)

    问题:session存验证码.本地拿postman测试了半天,都没有问题.   但到了小程序,服务端再获取(ctx.session.verifyCode)就一直提示不存在.undefined 小程序会 ...

  5. rabbitmq3.7.3 发布了一个新的 exchange x-random

    direct exchange 同一个 routing key 可以绑定多个 queue,当给这个routing key发消息时,所有 queue 都会投递.这个行为对于一些场景不适用,有时我们希望只 ...

  6. 【爬虫】爬虫简单举例(三种写法) 涉及requests、urllib、bs4,re

    目录 写法1:requests + re 写法2:urllib + re 方法3:request + bs4 补充.我在发了这篇文章之后,后面又要爬这个论坛.然后我发现我没有认真观察那个网页的源码,所 ...

  7. [转]在MyBatis中使用pageHelper5.1.9分页插件实现物理分页

    pagehelper的GIT地址:https://github.com/pagehelper/Mybatis-PageHelper/ 废话少说,直接给出中文官方链接: 1.如何使用分页插件 2.HOW ...

  8. Apgar score

    Apgar score Apgar is a quick test performed on a baby at 1 and 5 minutes after birth. The 1-minute s ...

  9. 今天记录一下css布局的flex布局的一个小妙招之gap

    在平常前端开发中,常见的开发布局flex布局,常见的布局有这个样子,这个是可以用css进行修改,但是今天分享一个简单的方法 这种布局的话,如果是偶数的话可以用flex的 justify-content ...

  10. linux 安装 Ollama 框架

    概述 Ollama 是一款旨在简化大语言模型(LLM)本地部署的工具,支持 Windows.Linux 和 MacOS 系统.它提供了一个用户友好的环境,让开发者可以轻松地运行和调优如 Qwen.Ll ...