万径人踪灭 bzoj-3160

题目大意:给定一个ab串。求所有的子序列满足:位置和字符都关于某条对称轴对称而且不连续。

注释:$1\le n\le 10^5$。


想法

看了大爷的题解,OrzOrz。

因为对称轴可以是两个字符中间的位置,所以我们把字符串按照$Manacher$的形式倍增。

我们希望处理出一个数组$f$,$f_i$表示以$i$为对称轴的左右相等字符个数。

以当前位置为对称轴的答案显然就是$2^{f_i}-1$。

因为还有不连续的条件,我们只需要减掉$Manacher$的回文半径即可。

现在考虑如何能求出$f$数组。

不难发现:其实原序列中的第$i$个字符如果和第$j$个字符相等那么会更新到倍增序列后的第$i+j$个字符。

所以$f_i=((\sum\limits_{j=0}^{i-1} (s[j]==s[i-j]))+1)/2$。

看起来像卷积的形式,想到$FFT$。

但是$FFT$只能做乘法,这个题怎么办?

我们先把所有的$a$字符都变成$1$,$b$字符变成$0$,然后统计$((\sum\limits_{j=0}^{i-1} a[j]\cdot a[i-j])+1)/2$。

再把所有的$b$字符变成$1$,$a$字符变成$0$。

用$FFT$优化卷积即可。

Code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define mod 1000000007
#define N 100010
using namespace std;
typedef long long ll;
typedef double db;
const db pi=acos(-1);
struct cp
{
db x,y;
cp() {x=y=0;}
cp(db x_,db y_){x=x_,y=y_;}
cp operator + (const cp &a) const {return cp(x+a.x,y+a.y);}
cp operator - (const cp &a) const {return cp(x-a.x,y-a.y);}
cp operator * (const cp &a) const {return cp(x*a.x-y*a.y,x*a.y+y*a.x);}
}a[N<<2];
void fft(cp *a,int len,int flg)
{
int i,j,k,t;
cp w,wn,tmp;
for(i=k=0;i<len;i++)
{
if(i>k) swap(a[i],a[k]);
for(j=len>>1;(k^=j)<j;j>>=1);
}
for(k=2;k<=len;k<<=1)
{
t=k>>1;
wn=cp(cos(2*pi*flg/k),sin(2*pi*flg/k));
for(i=0;i<len;i+=k)
{
w=cp(1,0);
for(j=i;j<i+t;j++)
{
tmp=a[j+t]*w;
a[j+t]=a[j]-tmp;
a[j]=a[j]+tmp;
w=w*wn;
}
}
}
if(flg==-1) for(i=0;i<len;i++) a[i].x/=len;
}
char s[N],t[N<<1];int f[N<<1],n,m,c[N<<2],ans,p[N<<2];
void manacher()
{
for(int i=0;i<n;i++)
{
t[++m]='#';
t[++m]=s[i];
}
t[++m]='#';
f[1]=0;
for(int now=1,i=1;i<=m;i++)
{
f[i]=min(f[(now<<1)-i],now+f[now]-i);
for(;i+f[i]<m&&i-f[i]>1;f[i]++) if(t[i+f[i]+1]!=t[i-f[i]-1]) break;
if(i+f[i]>now+f[now]) now=i;
ans-=(f[i]+1)>>1;
ans%=mod;
}
}
int main()
{
scanf("%s",s); n=strlen(s);
int len=1; while(len<(n<<1))len<<=1;
for(int i=0;i<n;i++) a[i].x=(s[i]=='a');
fft(a,len,1);
for(int i=0;i<len;i++) a[i]=a[i]*a[i];
fft(a,len,-1);
for(int i=0;i<len;i++) c[i]=(int)(a[i].x+0.1),a[i]=cp();
for(int i=0;i<n;i++) a[i].x=(s[i]=='b');
fft(a,len,1);
for(int i=0;i<len;i++) a[i]=a[i]*a[i];
fft(a,len,-1);
for(int i=0;i<len;i++) c[i]+=(int)(a[i].x+0.1);
manacher();
p[0]=1;
for(int i=1;i<len;i++) p[i]=(p[i-1]<<1)%mod;
for(int i=0;i<len;i++) ans=(ans+p[(c[i]+1)>>1]-1)%mod;
printf("%d\n",(ans+mod)%mod);
return 0;
}

小结:好题好题。比那个什么孤舟蓑笠翁友善多了。

  这个题主要是需要想到求$f$数组。而且连续的话需要用$Manacher$减掉,非常好的一道题。

[bzoj3160]万径人踪灭_FFT_Manacher的更多相关文章

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

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

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

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

  3. BZOJ3160万径人踪灭

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

  4. BZOJ3160: 万径人踪灭

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

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

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

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

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

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

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

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

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

  9. 多项式 之 快速傅里叶变换(FFT)/数论变换(NTT)/常用套路【入门】

    原文链接https://www.cnblogs.com/zhouzhendong/p/Fast-Fourier-Transform.html 多项式 之 快速傅里叶变换(FFT)/数论变换(NTT)/ ...

随机推荐

  1. Hadoop YARN学习之重要术语总结(6)

    Hadoop YARN学习之重要术语总结(6) - SLA服务等级 - RM(ResourceManager) - AM(ApplicationMaster) - NM(NodeMaster) - M ...

  2. 掌握Spark机器学习库-09.6-LDA算法

    数据集 iris.data 数据集概览 代码 package org.apache.spark.examples.examplesforml import org.apache.spark.ml.cl ...

  3. 2017huas_ACM第三天

    暑假集训第三天. 就在刚才AC了第十题,本周做题拿到了满分. 软件工程专业没有学习C++语言,这在做题过程中给了我不少的麻烦.遇到什么不懂的,不确认的,都要上网查阅或者开了新项目自己尝试一下.耗费了不 ...

  4. [6818开发板]八核开发板|4G开发板|GPS开发板|嵌入式开发平台

    IMX6开发板(基本型):960元 IMX6开发板(豪华型):1460元 S5P4418 核心板可以无缝支持核心系统S5P6818,并保持底板设计不变,将兼顾更高端 的应用领域,为项目和产品提供更好的 ...

  5. MySQL ORDER BY IF() 条件排序

    源 在做sqlzoo的时候,碰到一个SQL的排序问题,他把符合条件的单独几行,可以放在查询结果的开始,或者查询结果的尾部 通过的方法就是IN语句(也可以通过IF语句) 自己做了个测试,如下,这个是表的 ...

  6. Java中文乱码处理

    java编码转换过程 我们总是用一个java类文件和用户进行最直接的交互(输入.输出),这些交互内容包含的文字可能会包含中文.无论这些java类是与数据库交互,还是与前端页面交互,他们的生命周期总是这 ...

  7. python appium自动化,走过的坑

    使用的夜神模拟器,使用android5.1.1 第一坑:使用的android7.1.2,刚开始写好了登录的代码,需要的是滑屏进入到登录界面,结果运行的时候,没有自动滑屏就报错:因为运行时,报了一个进程 ...

  8. selenium抓取动态网页数据

    1.selenium抓取动态网页数据基础介绍 1.1 什么是AJAX AJAX(Asynchronouse JavaScript And XML:异步JavaScript和XML)通过在后台与服务器进 ...

  9. 通过反编译小程序来学习前端:wxappUnpacker

    小程序开发时,会有4种文件:.wxss  .json  .wxs  .wxml. 正式上传到腾讯时,目录会被打包,使用时再发放给客户端. 这个文件包后缀是 .wxapkg.只要手机用过这个小程序,文件 ...

  10. 零基础入门学习Python(1)--我和Python的第一次亲密接触

    前言 最近在学习Python编程语言,于是乎就在网上找资源.其中小甲鱼<零基础入门学习Python>试听了几节课,感觉还挺不错,里面的视频都是免费下载,小甲鱼讲话也挺幽默风趣的,所以呢,就 ...