【bzoj3160】 万径人踪灭
http://www.lydsy.com/JudgeOnline/problem.php?id=3160 (题目链接)
题意
给定一个由'a'和'b'构成的字符串,求不连续回文子序列的个数。
Solution
在膜拜了PoPoQQQ大爷的题解后,我觉得有必要自己写一发,感觉这道题倒还是可以理解的。
不连续的回文子序列个数感觉并不是特别好求,而不连续的回文子序列个数=回文子序列个数-连续回文子序列个数。后者很好办,就是${Manacher}$板子,考虑没有任何限制的回文子序列个数怎么求。
借用${Manacher}$的做法,先在字符串中添加分隔符,对于一个串${S}$长成这样:${aba}$,我们添加分隔符,那么得到${S'}$:${\$\#a\#b\#a\#}$
我们令${f_i}$表示以${i}$为中心的对称字符对的个数,那么很显然,以${i}$为中心的回文子序列的个数就等于${2^{f_i}-1}$,那么整个答案就等于:$${\sum_{i=1}^{2*n+1} {2^{f_i}-1}}$$
如果我们知道了${f_i}$,那么就可以算出答案了,而${f_i}$怎么求呢。
这里假设${S}$和${S'}$的下标都从${0}$开始(因为多项式的次数是从${0}$开始的,这样的话就可以避免一些下标的细节问题),如果${S'}$中的两个字母比如说这两个${a}$,它们是关于中间的${b}$对称的,想一想这两个${a}$与${b}$位置之间的关系:${S'_2=a,S'_6=a,S'_4=b}$,可以得到它们的下标:${x=2,y=6,mid=4}$,很显然:${x+y=2*mid}$。因为${S'}$中字母的下标都是偶数,我们将两边同时除以${2}$,得到这样一个式子:${x/2+y/2=mid}$。那么${x/2}$和${y/2}$表示什么呢,是不是就是${S'}$中的字母在原串${S}$中的位置${+1}$。那么我们可以得到这样一个结论:如果原串中两个字母${S_x=S_y}$,它们就会关于${S'_{(x+1)+(y+1)}}$对称。
那么我们就可以写出${f_i}$的表达式了:$${f_i=\lfloor{ \frac{1+\sum_{j=0}^{i-2} {[s_j=s_{i-2-j}]}} {2} }\rfloor }$$
这是一个卷积的形式,我们很容易想到用${FFT}$来解决这个东西。首先考虑${a}$对答案的贡献,令${a=1,b=0}$,求一遍${FFT}$;再考虑${b}$对答案的贡献,令${a=0,b=1}$,再求一遍${FFT}$;两者相加再加${1}$最后除以${2}$取下整就是${f}$了。代入之前的结论中即可出解。
话说我还是不会构造多项式,还是写一写吧。。比如说样例:${aba}$。我们考虑算${a}$的贡献:
$${A(x)=1*x^0+0*x^1+1*x^2}$$
$${B(x)=1*x^0+0*x^1+1*x^2}$$
那么最后的${f_i}$就是${A(x)*B(x)}$的第${i-1}$项的系数(次数为${i-2}$)。
细节
细节还是蛮多的,搞清楚下标始终是个问题。。注意数组大小,以及计算${f}$的时候要开LL。
代码
// bzoj3160
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<complex>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define MOD 1000000007
#define inf 1ll<<60
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std; typedef complex<double> E;
const int maxn=400010;
int bin[maxn],rev[maxn],f[maxn],p[maxn],n,L;
E a[maxn],b[maxn];
char s[maxn],st[maxn]; void FFT(E *a,int f) {
for (int i=0;i<n;i++) if (i<rev[i]) swap(a[i],a[rev[i]]);
for (int i=1;i<n;i<<=1) {
E wn(cos(Pi/i),f*sin(Pi/i));
for (int p=i<<1,j=0;j<n;j+=p) {
E w(1,0);
for (int k=0;k<i;k++,w*=wn) {
E x=a[k+j],y=a[k+j+i]*w;
a[k+j]=x+y;a[k+j+i]=x-y;
}
}
}
}
int Manacher(char *r,int len) {
st[0]='$';st[1]='#';
for (int i=0;i<len;i++) {
st[(i+1)<<1]=r[i];
st[(i+1)<<1|1]='#';
}
int mx=0,id,tot=0;
for (int i=1;i<2*len+1;i++) {
if (i<mx) p[i]=min(mx-i,p[id*2-i]);
while (st[i+p[i]]==st[i-p[i]]) p[i]++;
if (p[i]+i>mx) mx=p[i]+i,id=i;
tot=(tot+p[i]/2)%MOD;
}
return tot;
} int main() {
scanf("%s",s);
int len=strlen(s);
bin[0]=1;for (int i=1;i<maxn;i++) bin[i]=(bin[i-1]<<1)%MOD;
for (n=1;n<=len<<1;n<<=1) L++;
for (int i=0;i<n;i++) rev[i]=(rev[i>>1]>>1) | ((i&1)<<(L-1));
for (int i=0;i<len;i++) {
if (s[i]=='a') a[i]=1;
else a[i]=0;
}
FFT(a,1);
for (int i=0;i<n;i++) b[i]=a[i]*a[i];
memset(a,0,sizeof(a));
for (int i=0;i<len;i++) {
if (s[i]=='b') a[i]=1;
else a[i]=0;
}
FFT(a,1);
for (int i=0;i<n;i++) b[i]+=a[i]*a[i];
FFT(b,-1);
LL ans=0;
for (int i=2;i<2*len+1;i++) f[i]+=(LL)(b[i-2].real()+0.5)/n;
for (int i=2;i<2*len+1;i++) ans=(ans+bin[(f[i]+1)>>1]-1)%MOD;
printf("%lld",(ans+MOD-Manacher(s,len))%MOD);
return 0;
}
【bzoj3160】 万径人踪灭的更多相关文章
- [bzoj3160]万径人踪灭_FFT_Manacher
万径人踪灭 bzoj-3160 题目大意:给定一个ab串.求所有的子序列满足:位置和字符都关于某条对称轴对称而且不连续. 注释:$1\le n\le 10^5$. 想法: 看了大爷的题解,OrzOrz ...
- BZOJ3160 万径人踪灭 字符串 多项式 Manachar FFT
原文链接http://www.cnblogs.com/zhouzhendong/p/8810140.html 题目传送门 - BZOJ3160 题意 给你一个只含$a,b$的字符串,让你选择一个子序列 ...
- BZOJ3160 万径人踪灭(FFT+manacher)
容易想到先统计回文串数量,这样就去掉了不连续的限制,变为统计回文序列数量. 显然以某个位置为对称轴的回文序列数量就是2其两边(包括自身)对称相等的位置数量-1.对称有啥性质?位置和相等.这不就是卷积嘛 ...
- BZOJ3160万径人踪灭
Description Input & Output & Sample Input & Sample Output HINT 题解: 题意即求不连续但间隔长度对称的回文串个数. ...
- BZOJ3160: 万径人踪灭
设a[i]=bool(s[i]=='a'),b[i]=bool(s[i]=='b'),考虑a和a.b和b的卷积,由于卷积是对称的,就可以统计出不连续回文子串个数了.可能说得比较简略.再用manache ...
- bzoj千题计划302:bzoj3160: 万径人踪灭
https://www.lydsy.com/JudgeOnline/problem.php?id=3160 不连续的回文串数量=所有的回文序列数量-连续的回文子串 连续的回文子串: manacher ...
- BZOJ3160:万径人踪灭(FFT,Manacher)
Solution $ans=$回文子序列$-$回文子串的数目. 后者可以用$manacher$直接求. 前者设$f[i]$表示以$i$为中心的对称的字母对数. 那么回文子序列的数量也就是$\sum_{ ...
- BZOJ3160 万径人踪灭 【fft + manacher】
题解 此题略神QAQ orz po神牛 由题我们知道我们要求出: 回文子序列数 - 连续回文子串数 我们记为ans1和ans2 ans2可以用马拉车轻松解出,这里就不赘述了 问题是ans1 我们设\( ...
- BZOJ3160: 万径人踪灭(FFT,回文自动机)
BZOJ传送门: 解题思路: FFT在处理卷积时可以将自己与自己卷,在某一种字母上标1其他标0,做字符集次就好了. (回文就是直接对称可以联系偶函数定义理解,根据这个性质就可以将字符串反向实现字符串匹 ...
- 多项式 之 快速傅里叶变换(FFT)/数论变换(NTT)/常用套路【入门】
原文链接https://www.cnblogs.com/zhouzhendong/p/Fast-Fourier-Transform.html 多项式 之 快速傅里叶变换(FFT)/数论变换(NTT)/ ...
随机推荐
- 1.3《想成为黑客,不知道这些命令行可不行》(Learn Enough Command Line to Be Dangerous)——手册页
我们运行的命令行程序,通常在技术上称作shell, 它包含了一个非常强大(也很神秘)的工具,我们将用它来学习更多可用的命令.这个工具本身就是个称作'man'的命令('manual'的简写).它的参数是 ...
- 20155207 EXP7 网络欺诈技术防范
20155207 EXP7 网络欺诈技术防范 实验内容 本实践的目标理解常用网络欺诈背后的原理,以提高防范意识,并提出具体防范方法. 具体有 (1)简单应用SET工具建立冒名网站 (2)etterca ...
- Metasploit简单应用
什么是Metasploit Metasploit是一款开源的安全漏洞检测工具. 它可以帮助用户识别安全问题,验证漏洞的缓解措施,并对某些软件进行安全性评估,提供真正的安全风险情报.当我们第一次接触Me ...
- VS编程,WPF单独更改TextBlock中部分文字格式的一种方法
原文:VS编程,WPF单独更改TextBlock中部分文字格式的一种方法 版权声明:我不生产代码,我只是代码的搬运工. https://blog.csdn.net/qq_43307934/articl ...
- 对 JavaScript 中的5种主要的数据类型进行值复制
定义一个函数 clone(),可以对 JavaScript 中的5种主要的数据类型(包括 Number.String.Object.Array.Boolean)进行值复制 使用 typeof 判断值得 ...
- [BZOJ4082][Wf2014]Surveillance[倍增]
题意 给你一个长度为 \(len\) 的环,以及 \(n\) 个区间,要你选择尽量少的区间,使得它们完全覆盖整个环.问最少要多少个区间. \(len,n\leq 10^6\) . 分析 考虑普通的区间 ...
- Visual studio 2017中 Javascript对于Xrm对象模型没有智能提示的解决办法
Visual studio 2017中 Javascript对于Xrm对象模型没有智能提示的解决办法 先上个图.语法提示支持到 Microsoft Dynamics xRM API 8.2 也就是cr ...
- HTML表单与输入实例
解释HTML 表单用于搜集不同类型的用户输入.HTML 表单包含表单元素.表单元素指的是不同类型的 input 元素.复选框.单选按钮.提交按钮等等.<input> 元素<input ...
- 基于约束的SQL攻击
前言 值得庆幸的是如今开发者在构建网站时,已经开始注重安全问题了.绝大部分开发者都意识到SQL注入漏洞的存在,在本文我想与读者共同去探讨另一种与SQL数据库相关的漏洞,其危害与SQL注入不相上下,但却 ...
- jinkens 构建java及vue 项目