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

2023-11-10 21:41

本文主要是介绍BZOJ3160:万径人踪灭(FFT,Manacher),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Solution

$ans=$回文子序列$-$回文子串的数目。

后者可以用$manacher$直接求。

前者设$f[i]$表示以$i$为中心的对称的字母对数。

那么回文子序列的数量也就是$\sum_{i=0}^{n-1}2^{f[i]-1}$

构造两个数组$a[i],b[i]$。若第$i$位为$a$,那么$a[i]=1$,否则$b[i]=1$。

可以发现$a$数组自身卷积就是$a$字母对$f$数组的贡献,$b$数组同理。

卷下$a$,卷下$b$,对应位置求和,就是$f$数组。

因为在卷积中每对对称字符被算了两次,而自己和自己关于自己对称只算了一次,所以要把答案除2向上取整。

Code

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<cmath>
 5 #define N (400009)
 6 #define LL long long
 7 #define MOD (1000000007)
 8 using namespace std;
 9 
10 int n,fn,l,tot,r[N],len[N],p[N];
11 LL Re,fun;
12 char s[N],st[N];
13 double pi=acos(-1.0);
14 struct complex
15 {
16     double x,y;
17     complex (double xx=0,double yy=0)
18     {
19         x=xx; y=yy;
20     }
21 }a[N],b[N];
22 
23 complex operator + (complex a,complex b) {return complex(a.x+b.x,a.y+b.y);}
24 complex operator - (complex a,complex b) {return complex(a.x-b.x,a.y-b.y);}
25 complex operator * (complex a,complex b) {return complex(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
26 complex operator / (complex a,double b) {return complex(a.x/b,a.y/b);}
27 
28 void FFT(int n,complex *a,int opt)
29 {
30     for (int i=0; i<n; ++i)
31         if (i<r[i]) swap(a[i],a[r[i]]);
32     for (int k=1; k<n; k<<=1)
33     {
34         complex wn=complex(cos(pi/k),opt*sin(pi/k));
35         for (int i=0; i<n; i+=k<<1)
36         {
37             complex w=complex(1,0);
38             for (int j=0; j<k; ++j,w=w*wn)
39             {
40                 complex x=a[i+j], y=w*a[i+j+k];
41                 a[i+j]=x+y; a[i+j+k]=x-y;
42             }
43         }
44     }
45     if (opt==-1) for (int i=0; i<n; ++i) a[i]=a[i]/n;
46 }
47 
48 void Manacher()
49 {
50     s[++tot]='('; s[++tot]='#';
51     for (int i=0; i<n; ++i)
52         s[++tot]=st[i], s[++tot]='#';
53     s[++tot]=')';
54     int maxn=0,mid=0,x;
55     for (int i=1; i<=tot; ++i)
56     {
57         if (i>maxn) x=1;
58         else x=min(maxn-i+1,len[mid*2-i]);
59         while (s[i+x]==s[i-x]) x++;
60         len[i]=x;
61         if (i+x-1>maxn) maxn=i+x-1, mid=i;
62         fun=(fun+len[i]/2)%MOD;
63     }
64 }
65 
66 int main()
67 {
68     p[0]=1;
69     for (int i=1; i<=100000; ++i)
70         p[i]=p[i-1]*2%MOD;
71     scanf("%s",st);    n=strlen(st);
72     Manacher();
73 
74     fn=1;
75     while (fn<=n+n) fn<<=1, l++;
76     for (int i=0; i<fn; ++i)
77         r[i]=(r[i>>1]>>1) | ((i&1)<<(l-1));
78     for (int i=0; i<n; ++i)
79         if (st[i]=='a') a[i].x=1;
80         else b[i].x=1;
81     FFT(fn,a,1); FFT(fn,b,1);
82     for (int i=0; i<fn; ++i)
83         a[i]=a[i]*a[i], b[i]=b[i]*b[i];
84     FFT(fn,a,-1); FFT(fn,b,-1);
85     for (int i=0; i<fn; ++i)
86     {
87         int x=(a[i].x+b[i].x+0.5);
88         x=(x+1)>>1;
89         Re=(Re+p[x]-1)%MOD;
90     }
91     printf("%lld\n",(Re-fun+MOD)%MOD);
92 }

转载于:https://www.cnblogs.com/refun/p/10091484.html

这篇关于BZOJ3160:万径人踪灭(FFT,Manacher)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/385425

相关文章

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

【数字信号处理】一文讲清FFT(快速傅里叶变换)

目录 快速傅里叶变换(Fast Fourier Transform,FFT)FFT的背景快速傅里叶变换(Fast Fourier Transform,FFT)DFT的数学表达实际计算重要性和应用频谱泄露、频谱混叠奈奎斯特采样定理参考链接 快速傅里叶变换(Fast Fourier Transform,FFT) FFT的背景 1、为什么要时域→频域频率?50Hz+频率120Hz

【BNU】40719 Arithmetic Progressions【分块+FFT】

传送门:【BNU】40719 Arithmetic Progressions 题目分析: 用分块+FFT强行AC了这题…… 之前一直TLE……然后改了好久把姿势改的优美点了……终于过了…… 大概思路是:我们考虑分块,假设每一块的大小为S,一共分了B块然后我们分两种情况讨论: 1.第二个数在第i块,第一个数在(1~i-1)块内,第三个数在(i+1~B)块内。 2.至少两个数在同一块内。

【HDU】5197 DZY Loves Orzing 【FFT启发式合并】

传送门:【HDU】5197 DZY Loves Orzing 题目分析: 首先申明,我不会 dp dp方程= =……这个东西给队友找出来了,然后我就是套这个方程做题的Qrz…… 对于这题,因为 n2 n^2个数互不相同,所以每一列都可以单独考虑。设 dpni dp_ni表示长度为 n n的排列,能恰好看见ii个人的方案数,根据队友的发现, dpni dp_ni就等于 |sni| |s_ni|

【ZOJ】3874 Permutation Graph 【FFT+CDQ分治】

传送门:【ZOJ】3874 Permutation Graph 题目分析: 容易知道一个个连通块内部的标号都是连续的,否则一定会有另一个连通块向这个连通块建边,或者这个连通块向另一个连通块建边。而且从左到右左边的连通块内最大的标号小于右边连通块内最小的标号。 然后我们可以构造dp方程: dp[n]=n!−i!∗dp[n−i] \qquad \qquad dp[n] = n! - i! *

【SPOJ】Triple Sums【FFT】

传送门:【SPOJ】Triple Sums 题目分析: 首先我们不考虑 i<j<k i<j<k这个条件,构造多项式: Y=∑xai \qquad\qquad\qquad Y = \sum x^{a_i} 那么 ai+aj+ak=S ai+aj+ak=S的个数即 xai+aj+ak=S x^{a_i+a_j+a_k=S}的个数,等价于 Y3中xS Y^3中x^S的系数。 然后我们考虑容斥

【BNU】33943 Super Rooks on Chessboard 【FFT】

【BNU】33943 Super Rooks on Chessboard UVA上的题,然而我怎么会蠢到去UVA呢!(其实是百度首先跳出来的是BNU → \to_ → \to) 题目分析: 设 numx numx为 N N个车没有覆盖的行数,numynumy为 N N个车没有覆盖的列数。 首先我们考虑没有主对角线覆盖这一条件时,总共的没有被覆盖的面积就是numx∗numynumx \ast

【HDU】4609 3-idiots 【FFT】

传送门:【HDU】4609 3-idiots 题目分析: 我们考虑两边长度之和为 n n的方案数,设num[x]num[x]为长度为 x x的个数,那么∑nx=1num[n−x]∗num[x]\sum_{x=1}^{n}{num[n-x]*num[x]} 即两边长度之和为 n n的方案数。容易发现这这正是卷积!然后我们就可以愉快的用FFTFFT预处理出所有的两边长度之和为i的方案数。 FFT

【codechef】 Prime Distance On Tree【求树上路经长度为i的路径条数】【点分治+FFT】

传送门:【codechef】 Prime Distance On Tree 点分治+FFT水题……竟然n*n爆int没发现…… 而且NTT TLE,FFT跑的超级快…… my  code: my~~code: #include <bits/stdc++.h>using namespace std ;typedef long long LL ;#define clr( a , x ) m

【51nod】算法马拉松4 F 移数字 【快速求N!%P】【FFT】

传送门:【51nod】算法马拉松4 F 移数字 涉及知识点:多项式求逆,多项式除法,多点插值,阶乘取模。 对于N!%P,复杂度为 O(N−−√log2N−−√) O(\sqrt N \log^2\sqrt N)。 但常数巨大,和暴力算实际复杂度只相差常数= = 这个是可以扩展到组合数取模的~ my  code: my~~code: #include <stdio.h>#includ