bzoj 3160 万径人踪灭 FFT
万径人踪灭
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1936 Solved: 1076
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
Sample Output
HINT
题目大意:给定一个由'a'和'b'构成的字符串,求不连续回文子序列的个数
首先回文一定是将字符串倍增 由于求的是不连续回文子序列的个数 因此我们可以求出总回文子序列的个数,然后减掉连续的
连续的就是回文子串 用Manacher算法可以O(n)求解
不连续的就有些难搞了
首先我们令f[i]表示以i为中心的对称字符对个数
比如s[]=$#a#b#a 那么s[4]='b' f[4]=2
那么对于每个中心i我们有(2^f[i])-1种方案 答案即Σ[1<=i<=n*2+1]((2^f[i])-1)
问题就是如何求出f[]数组
我们发现对f[i]有贡献的一对字符在原字符串数组中的位置之和一定是i
比如str+1="aba" 那么第一个字符和第三个字符对倍增后的字符串的第4个位置有贡献
那么显然有f[i]=(Σ[1<=j<=i-1]bool(str[j]==str[i-j]))+1>>1 括号里面是一个卷积的形式 可以用FFT进行求解
首先考虑'a'对答案的贡献 那么令'a'=1 'b'=0 求出卷积就是'a'的贡献
再考虑'b'对答案的贡献 令'a'=0 'b'=1 求出卷积就是'b'的贡献
两次贡献之和+1>>1就是f[]数组 代入之前的结论中即可出解
其中的数值是0和1代入
1 #pragma GCC optimize(2) 2 #pragma G++ optimize(2) 3 #include<cstring> 4 #include<cmath> 5 #include<iostream> 6 #include<algorithm> 7 #include<cstdio> 8 9 #define mod 1000000007 10 #define ll long long 11 #define pi acos(-1) 12 #define N 300007 13 using namespace std; 14 inline int read() 15 { 16 int x=0,f=1;char ch=getchar(); 17 while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} 18 while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} 19 return x*f; 20 } 21 22 int n,m,len,L; 23 ll ans;char ch[N]; 24 int rev[N],bin[N],p[N]; 25 struct comp 26 { 27 double r,v; 28 void init(){r=v=0;} 29 inline comp operator+(const comp &a){return(comp){r+a.r,v+a.v};} 30 inline comp operator-(const comp &a){return(comp){r-a.r,v-a.v};} 31 inline comp operator*(const comp &a){return(comp){r*a.r-v*a.v,r*a.v+v*a.r};} 32 }a[N],f[N],g[N]; 33 34 void manacher() 35 { 36 ch[0]='+',ch[len+1]='-'; 37 int id,mx=0; 38 for(int i=1;i<=len;i++) 39 { 40 if(mx>i)p[i]=min(p[2*id-i],mx-i+1); 41 else p[i]=1; 42 while(ch[i+p[i]]==ch[i-p[i]])p[i]++; 43 if(i+p[i]-1>mx)mx=i+p[i]-1,id=i; 44 (ans-=p[i])%=mod; 45 } 46 mx=0; 47 for(int i=1;i<=len;i++) 48 { 49 if(mx>i)p[i]=min(mx-i,p[2*id-i]); 50 else p[i]=0; 51 while(ch[i+p[i]+1]==ch[i-p[i]])p[i]++; 52 if(i+p[i]>mx)mx=i+p[i],id=i; 53 (ans-=p[i])%=mod; 54 } 55 } 56 void FFT(comp *a,int f) 57 { 58 for(int i=0;i<n;i++)if(i<rev[i])swap(a[i],a[rev[i]]); 59 for(int i=1;i<n;i<<=1) 60 { 61 comp wn=(comp){cos(pi/i),f*sin(pi/i)}; 62 for (int j=0;j<n;j+=(i<<1)) 63 { 64 comp w=(comp){1,0}; 65 for (int k=0;k<i;k++,w=w*wn) 66 { 67 comp x=a[j+k],y=w*a[j+k+i]; 68 a[j+k]=x+y,a[j+k+i]=x-y; 69 } 70 } 71 } 72 if(f==-1)for (int i=0;i<n;i++)a[i].r/=n; 73 } 74 int main() 75 { 76 bin[0]=1;for (int i=1;i<=100000;i++)bin[i]=(bin[i-1]<<1)%mod; 77 scanf("%s",ch+1);len=strlen(ch+1); 78 manacher(); 79 m=2*(len-1);for(n=1;n<=m;n<<=1,L++);if(L)L--; 80 for(int i=0;i<n;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<L); 81 for (int i=0;i<len;i++)a[i].r=(ch[i+1]=='a')?1:0; 82 FFT(a,1); 83 for (int i=0;i<n;i++)f[i]=a[i]*a[i]; 84 FFT(f,-1); 85 for (int i=0;i<n;i++)a[i].init(); 86 for (int i=0;i<len;i++)a[i].r=(ch[i+1]=='b')?1:0; 87 FFT(a,1); 88 for (int i=0;i<n;i++)g[i]=a[i]*a[i]; 89 FFT(g,-1); 90 for (int i=0;i<n;i++) 91 { 92 int x=(int)(f[i].r+0.5)+(int)(g[i].r+0.5); 93 ans+=bin[(x+1)/2]-1; 94 ans%=mod; 95 } 96 printf("%lld",(ans+mod)%mod); 97 }