题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3160

求出关于一个位置有多少对对称字母,如果 i 位置有 f[i] 对,对答案的贡献是 2^f[i] - 1;

然后减去连续的,用 manachar 求出回文长度,每个位置作为边界都是一种不合法情况;

求对称,首先把字符串中间穿插字符 '$',于是字符串的长度变成2倍;

考虑一对字母 s[x],s[y],如果 s[x] = s[y],其对称中心是 (x+y)/2;

放在加入字符后的字符串中,对称中心就是 x+y;

所以可以看出卷积了:f[i] = ∑(0<=j<=i) (s[j]==s[i-j]),其中 i 视为新字符串中的位置,j 和 i-j 视为原字符串中的位置;

注意卷积和 manachar 算的个数都要包括自己成对,否则判断挺麻烦...

这里卷积的两个多项式其实是一样的,所以只要用 FFT 算出一个,然后自己乘起来即可;

做下一步的时候注意清空,别忘了清空 n~lim 部分的值;

处理 bin 的边界是 n 而非 n-1,因为最多可能有 n 对。

(学习了 manachar 的简洁写法)

代码如下:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. #include<cmath>
  6. using namespace std;
  7. typedef double db;
  8. int const xn=(<<),mod=1e9+;
  9. db const Pi=acos(-1.0);
  10. int n,rev[xn],lim=,l,len[xn],bin[xn],c[xn];
  11. char ch[xn];
  12. struct com{db x,y;}a[xn],b[xn],aa[xn];
  13. com operator + (com a,com b){return (com){a.x+b.x,a.y+b.y};}
  14. com operator - (com a,com b){return (com){a.x-b.x,a.y-b.y};}
  15. com operator * (com a,com b){return (com){a.x*b.x-a.y*b.y,a.x*b.y+b.x*a.y};}
  16. int upt(int x){while(x>=mod)x-=mod; while(x<)x+=mod; return x;}
  17. void fft(com *a,int tp)
  18. {
  19. for(int i=;i<lim;i++)
  20. if(i<rev[i])swap(a[i],a[rev[i]]);
  21. for(int mid=;mid<lim;mid<<=)
  22. {
  23. com wn=(com){cos(Pi/mid),tp*sin(Pi/mid)};
  24. for(int j=,len=(mid<<);j<lim;j+=len)
  25. {
  26. com w=(com){,};
  27. for(int k=;k<mid;k++,w=w*wn)
  28. {
  29. com x=a[j+k],y=w*a[j+mid+k];
  30. a[j+k]=x+y; a[j+mid+k]=x-y;
  31. }
  32. }
  33. }
  34. }
  35. void solve()
  36. {
  37. for(int i=;i<n;i++)a[i].x=(ch[i]=='a');
  38. fft(a,);
  39. for(int i=;i<lim;i++)b[i]=a[i]*a[i];
  40. for(int i=;i<n;i++)a[i].x=(ch[i]=='b'),a[i].y=;//y=0
  41. for(int i=n;i<lim;i++)a[i].x=,a[i].y=;//!!
  42. fft(a,);
  43. for(int i=;i<lim;i++)b[i]=b[i]+a[i]*a[i];
  44. fft(b,-);
  45. for(int i=;i<n+n;i++)c[i]=(c[i]+(int)(b[i].x/lim+0.5))%mod;
  46. }
  47. char s[xn];
  48. int manachar()//+i self
  49. {
  50. int mx=,id=,ret=; s[]='$';
  51. for(int i=;i<=n+n;i++)
  52. if(i%==)s[i]='$';
  53. else s[i]=ch[i>>];
  54. for(int i=;i<=n+n;i++)
  55. {
  56. if(i<mx)len[i]=min(mx-i,len[id*-i]);
  57. while(i-len[i]>=&&i+len[i]<=n+n&&s[i-len[i]]==s[i+len[i]])len[i]++;
  58. if(i+len[i]>mx)mx=i+len[i],id=i;
  59. ret=upt(ret+len[i]/);
  60. }
  61. return ret;
  62. }
  63. int main()
  64. {
  65. scanf("%s",ch); n=strlen(ch);
  66. while(lim<=n+n)lim<<=,l++;//
  67. for(int i=;i<lim;i++)
  68. rev[i]=((rev[i>>]>>)|((i&)<<(l-)));
  69. bin[]=;
  70. for(int i=;i<=n;i++)bin[i]=upt(bin[i-]+bin[i-]);
  71. solve();
  72. int ans=;
  73. for(int i=;i<n+n;i++)ans=upt(ans+bin[(c[i]+)>>]-);//+1 -1
  74. printf("%d\n",upt(ans-manachar()));
  75. return ;
  76. }

bzoj 3160 万径人踪灭 —— FFT的更多相关文章

  1. BZOJ 3160: 万径人踪灭 FFT+快速幂+manacher

    BZOJ 3160: 万径人踪灭 题目传送门 [题目大意] 给定一个长度为n的01串,求有多少个回文子序列? 回文子序列是指从原串中找出任意个,使得构成一个回文串,并且位置也是沿某一对称轴对称. 假如 ...

  2. BZOJ 3160: 万径人踪灭 [fft manacher]

    3160: 万径人踪灭 题意:求一个序列有多少不连续的回文子序列 一开始zz了直接用\(2^{r_i}-1\) 总-回文子串 后者用manacher处理 前者,考虑回文有两种对称形式(以元素/缝隙作为 ...

  3. bzoj 3160 万径人踪灭——FFT

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3160 似乎理解加深了. 用卷积算相同的位置:先把 a 赋成1. b 赋成0,卷积一遍:再把 ...

  4. bzoj 3160 万径人踪灭 FFT

    万径人踪灭 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1936  Solved: 1076[Submit][Status][Discuss] De ...

  5. bzoj 3160: 万径人踪灭 manachar + FFT

    3160: 万径人踪灭 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 133  Solved: 80[Submit][Status][Discuss] ...

  6. 【BZOJ】3160: 万径人踪灭 FFT+回文串

    [题意]给定只含'a'和'b'字符串S,求不全连续的回文子序列数.n<=10^5. [算法]FFT+回文串 [题解]不全连续的回文子序列数=回文子序列总数-回文子串数. 回文子串数可以用回文串算 ...

  7. bzoj 3160: 万径人踪灭【FFT+manacher】

    考虑正难则反,我们计算所有对称子序列个数,再减去连续的 这里减去连续的很简单,manacher即可 然后考虑总的,注意到关于一个中心对称的两点下标和相同(这样也能包含以空位为对称中心的方案),所以设f ...

  8. BZOJ 3160: 万径人踪灭

    Description 一个ab串,问有多少回文子序列,字母和位置都对称,并且不连续. Sol FFT+Manacher. 不连续只需要减去连续的就可以了,连续的可以直接Manacher算出来. 其他 ...

  9. BZOJ 3160 万径人踪灭 解题报告

    这个题感觉很神呀.将 FFT 和 Manacher 有机结合在了一起. 首先我们不管那个 “不能连续” 的条件,那么我们就可以求出有多少对字母关于某一条直线对称,然后记 $T_i$ 为关于直线 $i$ ...

随机推荐

  1. 查看java中的线程个数名称

    查看java中的线程个数名称 package com.stono.thread2; import java.lang.management.ManagementFactory; import java ...

  2. 转: 写给想成为前端工程师的同学们 (from 360前端团队)

    转自:     http://www.75team.com/post/to-be-a-good-frontend-engineer.html 前端工程师是做什么的? 前端工程师是互联网时代软件产品研发 ...

  3. node开发自动刷新网页中的css和javascript

    在已有node的环境下,安装browser-sync: npm install -g browser-sync 然后运行,默认本目录下(最后填写要监听的文件--本实例监听了css文件夹下面的所有css ...

  4. java性能监控工具jps-windows

    jps Lists the instrumented Java Virtual Machines (JVMs) on the target system. This command is experi ...

  5. CSS3中的动画效果-------Day72

    还记得么,在前面也曾实现过"仅仅用css让div动起来",还记得当时是怎么实现的么,是的,transition,针对的也比較局限,仅仅有旋转角度啊,长宽啊之类的,所以说,与其说是动 ...

  6. C#数据类型与数据库字段类型对应

    数据库 C#程序 int int32 text string bigint int64 binary System.Byte[] bit Boolean char string datetime Sy ...

  7. iOS 获取图片某一点的颜色对象(UIColor*)。

    - (UIColor *)colorAtPixel:(CGPoint)point { // Cancel if point is outside image coordinates if (!CGRe ...

  8. mysql could not be resolved: Name or service not known

    问题: mysql DNS反解:skip-name-resolve 错误日志有类似警告: 1.120119 16:26:04 [Warning] IP address '192.168.1.10' c ...

  9. 搭建mysql主从集群的步骤

    前提条件是:须要在linux上安装4个mysql数据库,都须要配置完对应的信息. 须要搭建: mysql 01: 主数据库  master                  mysql 02 :   ...

  10. SICP 习题 (1.38)解题总结

    SICP 习题1.38 紧跟着习题1.37的方向,要求我们用习题1.37中定义的cont-frac过程计算数学家欧拉大师在论文De Fractionibus Continuis 中提到的e-2的连分式 ...