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;
}

转载于:https://www.cnblogs.com/MashiroSky/p/6341296.html

【bzoj3160】 万径人踪灭相关推荐

  1. BZOJ3160:万径人踪灭

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

  2. BZOJ3160: 万径人踪灭

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

  3. manacher算法学习(求最长回文子串长度)

    Manacher总结 我的代码 学习:yyb luogu题目模板 xzy的模板 #include<iostream> #include<cstdlib> #include< ...

  4. 【BZOJ3160】万径人踪灭 Manacher+FFT

    [BZOJ3160]万径人踪灭 Description Input Output Sample Input Sample Output HINT 题解:自己想出来1A,先撒花~(其实FFT部分挺裸的) ...

  5. 【bzoj3160】万径人踪灭

    题意:给一个只含a.b的字符串,求所有的回文不连续子序列. manacher+FFT. 先求出所有回文序列,再减去连续子序列(即回文串). 将a.b分开考虑,对于一个对称轴,以其为回文中心的回文序列的 ...

  6. 【BZOJ3160】 万径人踪灭(FFT,manacher)

    前言 多项式真的很难♂啊qwq Solution 考虑求的是一个有间隔的回文串,相当于是: 总的答案-没有间隔的答案 考虑总的答案怎么计算?FFT卷一下就好了. 对于每一位字符,有两种取值,然后随便卷 ...

  7. 【BZOJ 3160】 3160: 万径人踪灭 (FFT)

    3160: 万径人踪灭 Time Limit: 10 Sec  Memory Limit: 256 MB Submit: 1440  Solved: 799 Description Input Out ...

  8. 洛谷P4199 万径人踪灭(manacher+FFT)

    传送门 题目所求为所有的不连续回文子序列个数,可以转化为回文子序列数-回文子串数 回文子串manacher跑一跑就行了,考虑怎么求回文子序列数 我们考虑,如果$S_i$是回文子序列的对称中心,那么只要 ...

  9. bzoj3160(FFT+回文自动机)

    题目描述 https://www.lydsy.com/JudgeOnline/problem.php?id=3160 题解 先把问题转化一下,我们要求的是非连续对称回文子序列. ans=回文子序列数- ...

  10. 20178.27 万径人踪灭 思考记录

    字符串的题也可以fft. 只要能化成卷积的形式就都可以fft 比如这里的回文:    对一个位置:+1 -1 +2 -2  他们和相等,所以对a跑一边,对b跑一遍,就相当于建出n次多项式然后求系数 注 ...

最新文章

  1. Error creating bean with name 'multipleEntityManagerFactory' defined in class
  2. 沈阳人才市场7月精品招聘会
  3. 《软件需求模式》阅读笔记04
  4. 《复杂》读书笔记(part2)--混沌与逻辑斯蒂映射
  5. Java数学工具类MathUtil
  6. python代码_零基础小白必看篇:Python代码注释规范代码实例解析操作(收藏)
  7. 孩子上了高一突然学不懂了,该怎么办?
  8. C++(八)— 死锁原因及解决方法
  9. PDG转图像、PDF的若干方法
  10. wxpython使用_wxpython的demo使用
  11. 单例模式(懒汉,饿汉)
  12. Mockito使用简介
  13. Elmo NAACl 2018
  14. 基于MDK开发的TencentOS-Tiny软件包,快速移植物联网操作系统到Keil中!
  15. 白盒测试与黑盒测试的比较
  16. JS特效-星空太空效果-极简
  17. 【测绘程序设计】——空间直角坐标转换
  18. 印章智能管控方案,帮助企业全维度管控印章
  19. 防静电手环在计算机中的功能,防静电手环原理
  20. 零基础转行可以做软件测试吗?

热门文章

  1. 澳大利亚加密货币借记卡将兼容三万台ATM和一百万台支付终端
  2. django Model field
  3. 引入第三方jar包编译正常,运行报错的问题解决方法
  4. Windows装机必备——WinRAR2023最新版下载安装教程
  5. 最小二乘法的正交多项拟合算法
  6. 在springmvc的Filter过滤器中更改请求参数,servletRequest.getParameter或者servletRequest.getParameterMap的参数教程
  7. 国庆长假引爆新零售 天搜科技如何“加持”实体店变革
  8. 芬兰对全球开放免费在线AI课程
  9. 2012第三届蓝桥杯软件大赛Java语言本科组初赛试题
  10. 基于javaweb的大学生健康档案管理系统(java+jpa+swagger-ui+springboot+vue+mysql)