bzoj 3160: 万径人踪灭【FFT+manacher】
考虑正难则反,我们计算所有对称子序列个数,再减去连续的
这里减去连续的很简单,manacher即可
然后考虑总的,注意到关于一个中心对称的两点下标和相同(这样也能包含以空位为对称中心的方案),所以设f[i]为下标和为i的对称中心一共有多少对相同字符,这样总答案就是\( \sum_{i=0}{2*n-2}2{f[i]}-1 \)(减掉的1是减掉空集)
然后考虑f怎么求,\( f[i]=((\sum_{j=0}^{i-1}s[j]s[i-j])+1)/2 \),除2是因为每一对都被算了两遍
暴力是不行的,但是这个(j,i-j)看着非常卷积,所以考虑怎么用FFT优化一下,把a字符和b字符分开算,以算a字符为例,做一个数组a[i]=(s[i]'a')?1:0,然后多项式是\( \sum_{j=0}^{i-1}a[j]*a[i-j]) \),这样就只算了对称且两点都是a的方案数,b同理
然后减掉manacher结果即可
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int N=500005,mod=1e9+7;
int n,f[N],bt,lm,re[N];
long long ans;
char c[N],s[N];
struct cd
{
double a,b;
cd(double A=0,double B=0)
{
a=A,b=B;
}
cd operator + (const cd &x) const
{
return cd(a+x.a,b+x.b);
}
cd operator - (const cd &x) const
{
return cd(a-x.a,b-x.b);
}
cd operator * (const cd &x) const
{
return cd(a*x.a-b*x.b,a*x.b+b*x.a);
}
}a[N],b[N];
void dft(cd a[],int f)
{
for(int i=0;i<lm;i++)
if(i<re[i])
swap(a[i],a[re[i]]);
for(int i=1;i<lm;i<<=1)
{
cd wi=cd(cos(M_PI/i),f*sin(M_PI/i));
for(int k=0;k<lm;k+=(i<<1))
{
cd w=cd(1,0),x,y;
for(int j=0;j<i;j++)
{
x=a[j+k],y=w*a[i+j+k];
a[j+k]=x+y,a[i+j+k]=x-y;
w=w*wi;
}
}
}
if(f==-1)
for(int i=0;i<lm;i++)
a[i].a/=lm;
}
long long ksm(long long a,long long b)
{
long long r=1;
while(b)
{
if(b&1)
r=r*a%mod;
a=a*a%mod;
b>>=1;
}
return r;
}
int main()
{
scanf("%s",c);
n=strlen(c);
for(bt=0;(1<<bt)<=2*n;bt++);
lm=(1<<bt);
for(int i=0;i<lm;i++)
re[i]=(re[i>>1]>>1)|((i&1)<<(bt-1));
for(int i=0;i<lm;i++)
a[i].a=(c[i]=='a')?1:0,a[i].b=0;
dft(a,1);
for(int i=0;i<lm;i++)
b[i]=a[i]*a[i];
for(int i=0;i<lm;i++)
a[i].a=(c[i]=='b')?1:0,a[i].b=0;
dft(a,1);
for(int i=0;i<lm;i++)
b[i]=b[i]+a[i]*a[i];
dft(b,-1);
for(int i=0;i<=2*(n-1);i++)
ans=(ans+ksm(2,((int)(b[i].a+0.5)+1)/2)-1)%mod;//cerr<<ans<<endl;
for(int i=0;i<n;i++)
s[(i+1)*2]=c[i],s[(i+1)*2+1]='#';
s[0]='$',s[1]='#',s[2*n+2]='&';
for(int i=1,mx=0,w;i<2*n+1;i++)
{
if(i<mx)
f[i]=min(f[2*w-i],mx-i);
else
f[i]=1;
for(;s[i-f[i]]==s[i+f[i]];f[i]++);
if(i+f[i]>mx)
mx=i+f[i],w=i;
ans=(ans-f[i]/2+mod)%mod;
}
printf("%lld\n",(ans%mod+mod)%mod);
return 0;
}
bzoj 3160: 万径人踪灭【FFT+manacher】的更多相关文章
- BZOJ 3160: 万径人踪灭 [fft manacher]
3160: 万径人踪灭 题意:求一个序列有多少不连续的回文子序列 一开始zz了直接用\(2^{r_i}-1\) 总-回文子串 后者用manacher处理 前者,考虑回文有两种对称形式(以元素/缝隙作为 ...
- BZOJ 3160: 万径人踪灭 FFT+快速幂+manacher
BZOJ 3160: 万径人踪灭 题目传送门 [题目大意] 给定一个长度为n的01串,求有多少个回文子序列? 回文子序列是指从原串中找出任意个,使得构成一个回文串,并且位置也是沿某一对称轴对称. 假如 ...
- bzoj 3160 万径人踪灭 FFT
万径人踪灭 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1936 Solved: 1076[Submit][Status][Discuss] De ...
- bzoj 3160 万径人踪灭——FFT
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3160 似乎理解加深了. 用卷积算相同的位置:先把 a 赋成1. b 赋成0,卷积一遍:再把 ...
- bzoj 3160 万径人踪灭 —— FFT
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3160 求出关于一个位置有多少对对称字母,如果 i 位置有 f[i] 对,对答案的贡献是 2^ ...
- bzoj 3160: 万径人踪灭 manachar + FFT
3160: 万径人踪灭 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 133 Solved: 80[Submit][Status][Discuss] ...
- BZOJ 3160: 万径人踪灭
Description 一个ab串,问有多少回文子序列,字母和位置都对称,并且不连续. Sol FFT+Manacher. 不连续只需要减去连续的就可以了,连续的可以直接Manacher算出来. 其他 ...
- 【BZOJ】3160: 万径人踪灭 FFT+回文串
[题意]给定只含'a'和'b'字符串S,求不全连续的回文子序列数.n<=10^5. [算法]FFT+回文串 [题解]不全连续的回文子序列数=回文子序列总数-回文子串数. 回文子串数可以用回文串算 ...
- BZOJ 3160 万径人踪灭 解题报告
这个题感觉很神呀.将 FFT 和 Manacher 有机结合在了一起. 首先我们不管那个 “不能连续” 的条件,那么我们就可以求出有多少对字母关于某一条直线对称,然后记 $T_i$ 为关于直线 $i$ ...
随机推荐
- apache多网站配置
前言 虽说apache安装好后给了我们一个默认的一个网站.并且我们还能够将这个默认的网站改动成我们自己的网站.可是这似乎还不能全然满足我们的须要,由于当我们要在本机上开发(phpWeb)或者測试另外 ...
- MVC框架的优缺点
MVC框架的优缺点 解析:M(Model)-模型,V(View)-视图.C(Controller)-控制器 作用:M-处理应用程序数据部分,V-处理数据展示的部分.C-处理用户交互,逻辑功能实现 1. ...
- selenium-python问题日记
今天在学习selenium时遇到了两个问题,在这里记录一下: 使用unittest框架组织了测试用例后,拓展一下功能就成了我最想做的事情, 所以决定添加发邮件功能. 使用python自带的smtpli ...
- 使用外部 toolchain 编译 openwrt
默认编译 openwrt 时会先编译一套 toolchain. 这个步骤耗时较长. 使用外部 toolchain 可以多个 project 共用一套 toolchain , 而且也不重再编译它了. 省 ...
- Arcgis Engine(ae)接口详解(5):IGeometry几何高级操作
IPoint point = new PointClass(); point.PutCoords(, ); //ITopologicalOperator接口用于几何对象的几何操作 ITopologic ...
- Web 监听器
什么事web 监听器? Servlet规范中定义的一种特殊类 用于监听ServletContext.HttpSession和ServletRequest等象的创建与销毁的事件 用监听域对象的属性发生修 ...
- mvn_action
validate(验证): 验证项目正确,并且所有必要信息可用. compile(编译): 编译项目源码 test(测试): 使用合适的单元测试框架测试编译后的源码. package(打包): 源码编 ...
- isMemberOf与isKindOf的区别
这两个方法常常会困惑我们,它们有什么区别呢? 定义 首先,我们来看看它们的定义. isKindOfClass: 官方解释:Returns a Boolean value that indicates ...
- ActiveMQ 入门使用p2p模型-主动消费
生产者 package clc.active; import com.sun.xml.internal.bind.v2.runtime.unmarshaller.XmlVisitor; import ...
- Java 深拷贝浅拷贝 与 序列化
一.浅拷贝.深拷贝 浅拷贝会对对象中的成员变量进行拷贝:如果是基本类型,拷贝的就是基本类型的值:如果属性是内存地址(引用类型),拷贝的就是内存地址 : 深拷贝,除了基本类型外,引用类型所引用的对象也会 ...