[bzoj3160]万径人踪灭

Manacher+FFT,这题太精妙了,我现在才写是不是太弱了...

Ans=以某个轴为中心的每一种回文子序列-所有连续回文串方案数

连续部分可以用Manacher在O(n)时间内解决。

第一部分:令f[i]=以i为中轴的对称对数,则对(2^f[i])-1求和即可(不能光有一根轴)

长串中i左右对称的对数位置相加一定是i(在短串中),那么f[i]=[sigma((str[x]==str[i-x])(x<i))+1]/2

这时题目还有个条件哟~串只是由a,b构成的,我们考虑一个卷积的形式C[k]=sigma(a[x]*b[k-x],0<=x<=k),与上面是如出一辙的,只需分别考虑a,b的贡献做两个FFT。

能独立推出来的人都是大大大神....Orz PoPoQQQ!

细节还是有点多,特别要注意长串与短串的下标(有没有插特殊符号)。

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<complex>
 4 #include<cstring>
 5 #include<algorithm>
 6 #define ll long long
 7 #define N 502020
 8 #define mo 1000000007
 9 using namespace std;
10 typedef complex<double> E;
11 const double pi=acos(-1);
12 int n,m,len,p[N],R[N],L;
13 char str[N];
14 ll ans=0,ans1=0,bin[N];
15 E a[N],f[N],g[N];
16 void manacher(){
17     str[0]=‘-‘;str[len+1]=‘+‘;
18     int id,mx=0;
19     for(int i=1;i<=len;i++){
20         if(mx>i)p[i]=min(mx-i+1,p[2*id-i]);else p[i]=1;
21         while(str[i+p[i]]==str[i-p[i]])p[i]++;
22         if(i+p[i]-1>mx)mx=i+p[i]-1,id=i;
23         ans1=(ans1+p[i])%mo;
24     }id=0,mx=0;
25     for(int i=1;i<=len;i++){
26         if(mx>i)p[i]=min(mx-i,p[2*id-i]);else p[i]=0;
27         while(str[i+p[i]+1]==str[i-p[i]])p[i]++;
28         if(i+p[i]>mx)mx=i+p[i],id=i;
29         ans1=(ans1+p[i])%mo;
30     }
31 }
32 void fft(E *a,int f){
33     for(int i=1;i<n;i++)if(i>R[i])swap(a[i],a[R[i]]);
34     for(int i=1;i<n;i<<=1){
35         E wn(cos(pi/i),sin(pi/i)*f);
36         for(int j=0;j<n;j+=i<<1){
37             E w(1,0);
38             for(int k=0;k<i;k++,w*=wn){
39                 E x=a[j+k],y=w*a[j+k+i];
40                 a[j+k]=x+y;a[j+k+i]=x-y;
41             }
42         }
43     }
44     if(f==-1)for(int i=0;i<n;i++)a[i]/=n;
45 }
46 int main()
47 {
48     scanf("%s",str+1);len=strlen(str+1);
49     bin[0]=1;for(int i=1;i<=100000;i++)bin[i]=bin[i-1]*2%mo;
50     manacher();
51     m=2*(len-1);for(n=1;n<=m;n*=2)L++;
52     for(int i=1;i<n;i++)R[i]=(R[i/2]/2)|((i&1)<<(L-1));
53     for(int i=0;i<len;i++)a[i]=(str[i+1]==‘a‘);
54     fft(a,1);for(int i=0;i<n;i++)f[i]=a[i]*a[i];fft(f,-1);
55     memset(a,0,sizeof(a));
56     for(int i=0;i<len;i++)a[i]=(str[i+1]==‘b‘);
57     fft(a,1);for(int i=0;i<n;i++)g[i]=a[i]*a[i];fft(g,-1);
58     for(int i=0;i<n;i++){
59         int x=f[i].real()+g[i].real()+0.1;
60         ans=(ans+bin[(x+1)/2])%mo;
61         ans=(ans-1+mo)%mo;
62     }
63     //printf("%lld %lld\n",ans,ans1);
64     printf("%lld\n",(ans-ans1+mo)%mo);
65     return 0;
66 }

代码还是看hzwer的好

最后想说一下n与m的关系,假设要求0...n,m=2×n之后,n变成了大于m的2的幂次。

但是最后答案是在0...n×2中的。

像2194那个题,题面给出的信息经转化之后便可看成两个多项式相乘,对应的下标就是对应的次数。都是有道理的。

= =Manacher不会背

时间: 2024-08-04 04:09:29

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

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

原文链接http://www.cnblogs.com/zhouzhendong/p/8810140.html 题目传送门 - BZOJ3160 题意 给你一个只含$a,b$的字符串,让你选择一个子序列,使得: $1.$位置和字符都关于某一条对称轴对称. $2.$不能是连续的一段. 问原来的字符串中能找出多少个这样的子序列.答案对$10^9+7$取模. 串长$\leq 10^5$. 题解 下面的讨论都在满足条件$1$的情况下进行. 首先,我们先不考虑条件$2$.然后再减掉不满足条件$2$的就可以了

BZOJ3160万径人踪灭

题解: 题意即求不连续但间隔长度对称的回文串个数. 若si=sj,则这对字符可以作为以(i+j)/2为中心的回文串的一部分. 用F[i]来表示可以做为以i/2为中心的回文串的一部分的字符对数,则以i/2为中心的回文串数为2^F[i]. 则这就成了多项式乘法:先做一次a的,把字符为a的位置值赋为1,其余为0,进行一次FFT:同理做一次b的. 因为完全连续是不可以的,所以用Manacher求出这样的回文串的个数并减去. 代码: (BZOJ上PASCAL跑得不够快,再加上这题时限只有10s,并没有AC

BZOJ3160 万径人踪灭 【fft + manacher】

题解 此题略神QAQ orz po神牛 由题我们知道我们要求出: 回文子序列数 - 连续回文子串数 我们记为ans1和ans2 ans2可以用马拉车轻松解出,这里就不赘述了 问题是ans1 我们设\(f[i]\)表示以i位置为中心的对称的字符对数,那么i位置产生的回文子序列数 = \(2^{f[i]} - 1\) 如何求? 由对称的性质,以i为对称中心的两点\(a,b\)满足\(a+b=2*i\) 我们可以设一个这样的序列: \(c[n]\)表示以\(n/2\)位置为对称点的对称点对数[n/2若

目前的字符串

Aho-Corasick automaton:BZOJ4820[bzoj2754][SCOI2012]喵星球上的点名后缀数组:BZOJ4310 跳蚤manacher: BZOJ3160万径人踪灭Palindromic Tree:bzoj4044Bzoj3676:[Apio2014]回文串 bzoj 1559 ** ac+jvchengBZOJ1195:[HNOI2006]最短母串 ** ac+jvchengbzoj 1692 * sabzoj 1031 * sabzoj 3796 ** sa+k

字符串题表

已完成bzoj1559 ** ac+jvchengbzoj1195:[HNOI2006]最短母串 ** ac+jvchengbzoj1692 * sabzoj1031 * sabzoj3796 ** sa+kmpbzoj3230:相似子串 ** sa+stbzoj4698 *** sabzoj2160:拉拉队排练 * manacherbzoj3790 * manacher+tanxinbzoj2565:最长双回文串 * manacher+luangaobzoj1414:[ZJOI2009]对称的

关于万恶的多项式

模板: 1 //Achen 2 #include<algorithm> 3 #include<iostream> 4 #include<cstring> 5 #include<cstdlib> 6 #include<vector> 7 #include<cstdio> 8 #include<queue> 9 #include<cmath> 10 #include<set> 11 #include&l

【BZOJ3160】万径人踪灭 Manacher+FFT

[BZOJ3160]万径人踪灭 Description Input Output Sample Input Sample Output HINT 题解:自己想出来1A,先撒花~(其实FFT部分挺裸的) 做这道题,第一思路很重要,显然看到这题的第一想法就是ans=总数-不合法(不要问我为什么显然).因为向这种用补集法的题一般都会给一些很奇葩的限制条件,但是一旦换个角度去想就很水了,好了不多说废话了. 显然,不合法的情况,也就是连续的回文区间的方案数,我们直接上Manacher就搞定了嘛!答案就是所

【bzoj3160】 万径人踪灭

http://www.lydsy.com/JudgeOnline/problem.php?id=3160 (题目链接) 题意 给定一个由'a'和'b'构成的字符串,求不连续回文子序列的个数. Solution 在膜拜了PoPoQQQ大爷的题解后,我觉得有必要自己写一发,感觉这道题倒还是可以理解的. 不连续的回文子序列个数感觉并不是特别好求,而不连续的回文子序列个数=回文子序列个数-连续回文子序列个数.后者很好办,就是Manacher板子,考虑没有任何限制的回文子序列个数怎么求. 借用${Mana

【bzoj3160】万径人踪灭 FFT

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3160 我是一个傻叉 微笑脸 1 #include<bits/stdc++.h> 2 #define inf 1000000000 3 #define ll long long 4 #define N 200005 5 #define mod 1000000007 6 using namespace std; 7 int read(){ 8 int x=0,f=1;char ch=getch