bzoj3160 萬徑人蹤滅
原題地址:http://www.lydsy.com/JudgeOnline/problem.php?id=3622
題意:
給定一個長度爲N且只有a,b的字符串,問有多少種方案從中選取一個子序列,使得:
1.位置和字符都關於某條對稱軸對稱。
2.不能是連續的一段。
數據範圍
n<=100000
題解:
首先求不連續的,就先求所有的,再用manacher求連續的剪掉即可。
關鍵大概就是想到以每個位置爲中心,兩邊對稱相同的有多少對 ,這個中心的答案就是 。
當然有夾縫處,於是我們把i數組下標擴大一倍:
,這是一個卷積的形式。
介於0x0=0,1x0=0,1x1=1,
我們想到了規定某一種字符係數爲1,然後fft做多項式乘法,這樣只有相同的纔會貢獻。
對a做一遍FFT,對b做一遍FFT,加一起再IDFT,得到 數組,減去manacher的答案即可。
代碼:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#define LL long long
using namespace std;
const int mod=1000000007;
const int MXN=530000;
const double Pi=acos(-1);
struct Virt
{
double r,i;
Virt(){}
Virt(double r,double i):r(r),i(i){}
Virt operator+(const Virt &A){return Virt(r+A.r,i+A.i);}
Virt operator-(const Virt &A){return Virt(r-A.r,i-A.i);}
Virt operator*(const Virt &A){return Virt(r*A.r-i*A.i,r*A.i+i*A.r);}
}omg[MXN],_omg[MXN],a[MXN],b[MXN],c[MXN];
int len,n,p,R[MXN],po[MXN],v[MXN];
char s[MXN];
void FFT(Virt *x,int opt)
{
Virt *w; if(opt==1) w=omg; else w=_omg;
for(int i=0;i<n;i++) if(i<R[i]) swap(x[i],x[R[i]]);
for(int m=2;m<=n;m=m<<1)
{
int l=m>>1;
for(int j=0;j<n;j+=m)
{
for(int i=0;i<l;i++)
{
Virt y=x[j+i+l]*w[n/m*i];
x[j+i+l]=x[j+i]-y;
x[j+i]=x[j+i]+y;
}
}
}
if(opt==-1) for(int i=0;i<n;i++) x[i].r=x[i].r/(double)n;
}
int manacher()
{
for(int i=len;i>=0;i--) s[2*i+1]='#',s[2*i+2]=s[i]; s[0]='+'; s[2*len+2]='-';
int mx=0,id=0; int ret=0;
for(int i=1;i<=2*len;i++)
{
if(id+mx>i) v[i]=min(v[2*id-i],id+mx-i);
else v[i]=1;
while(s[i+v[i]]==s[i-v[i]]) v[i]++;
if(i+v[i]>id+mx) id=i,mx=v[i];
ret=(ret+v[i]/2)%mod;
}
return ret;
}
int main()
{
scanf("%s",s); len=strlen(s);
int m; for(p=0,n=1,m=2*len;n<m;n=n<<1,p++);
po[0]=1; for(int i=1;i<=n;i++) po[i]=(po[i-1]*2)%mod;
R[0]=0; for(int i=1;i<n;i++) {R[i]=(R[i>>1]>>1)|((i&1)<<(p-1));}
for(int i=0;i<n;i++){omg[i]=Virt(cos(2.0*Pi/(double)n*i),sin(2.0*Pi/(double)n*i)); _omg[i]=Virt(omg[i].r,-omg[i].i);}
for(int i=0;i<n;i++) {a[i]=Virt((s[i]=='a'),0); b[i]=Virt((s[i]=='b'),0);}
FFT(a,1); FFT(b,1);
for(int i=0;i<n;i++) c[i]=a[i]*a[i]+b[i]*b[i];
FFT(c,-1);
int ret=0; for(int i=0;i<n;i++) {ret=(ret+po[((int)(c[i].r+0.5)+1)/2])%mod; ret--; if(ret<0) ret+=mod;}
ret=(ret-manacher()+mod)%mod;
printf("%d\n",ret);
return 0;
}