BZOJ 3160 万径人踪灭
题意:
在一个仅含有$a,b$的字符串里选取一个子序列,使得:
1.位置和字符都关于某条对称轴对称;
2.不能是连续的一段。
题解:
很久以前写的题解太扯淡了。。重新写一篇
首先对于限制$2$我们可以把它转化成没有限制-连续回文子串
然后我们发现问题等价于枚举对称轴然后求有几个位置关于它对称
至今不会manacher于是用hash(哪有题目会卡这个log的)
暴力是$n^2$的 和位置有关的匹配考虑一下$FFT$
两个位置关于$i$对称的话,一个是i-k,一个是i+k
发现他们的下标和是2*i
这说明了我们只需要自己卷自己就好了
如何卷呢,我们要保证$aa=1,bb=1,ab=ba=0$
令a的位置权值为0,b的位置权值为1
直接算相同地方式子会比较复杂$({(a[x]-a[y])}^2-1)^2$
我们可以容斥一下算不同的,那么就是$(a[x]-a[y])^2$
展开一下套fft就可以了
代码:
#include<bits/stdc++.h> using namespace std; #define rint register int #define IL inline #define rep(i,h,t) for (int i=h;i<=t;i++) #define dep(i,t,h) for (int i=t;i>=h;i--) #define me(x) memset(x,0,sizoef(x)) #define mep(x,y) memcpy(x,y,sizeof(y)) #define ll long long #define mid ((h+t+1)>>1) #define ull unsigned ll namespace IO{ char ss[1<<24],*A=ss,*B=ss; IL char gc() { return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++; } template<class T>IL void read(T &x) { rint f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48); while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); } char sr[1<<24],z[20]; int Z,C=-1; template<class T>IL void wer(T x) { if (x<0) sr[++C]='-',x=-x; while (z[++Z]=x%10+48,x/=10); while (sr[++C]=z[Z],--Z); } IL void wer1() {sr[++C]=' ';} IL void wer2() {sr[++C]='\n';} template<class T>IL void maxa(T &x,T y) {if (x<y) x=y;} template<class T>IL void mina(T &x,T y) {if (x>y) x=y;} template<class T>IL T MAX(T x,T y) {return x>y?x:y;} template<class T>IL T MIN(T x,T y) {return x<y?x:y;} }; using namespace IO; const int N=6e5; const int mo=1e9+7; const double pi=acos(-1); struct cp{ double x,y; cp operator + (const cp o) const { return (cp){o.x+x,o.y+y}; } cp operator - (const cp o) const { return (cp){x-o.x,y-o.y}; } cp operator * (const cp o) const { return (cp){x*o.x-y*o.y,x*o.y+y*o.x}; } }w[N],a[N],b[N]; char s[N]; int t[N],n,m,A1[N],B1[N],sum[N],jl[N]; ull jd[N],hash1[N],hash2[N]; IL int fsp(int x,int y) { ll ans=1; while (y) { if (y&1) ans=ans*x%mo; x=1ll*x*x%mo; y>>=1; } return ans; } IL bool check(int x1,int y1,int x2,int y2) { if ((hash1[y1]-hash1[x1-1])*jd[n-x1]==(hash2[x2]-hash2[y2+1])*jd[y2-1]) return(1); else return(0); } int l,r[N]; void fft_init() { l=0; for (n=1;n<=m;n<<=1) l++; for (int i=0;i<n;i++) r[i]=(r[i/2]/2)|((i&1)<<(l-1)); for (int i=0;i<n;i++) w[i]=(cp){cos(pi*i/n),sin(pi*i/n)}; } void fft_clear() { rep(i,0,n) a[i].x=a[i].y=b[i].x=b[i].y=0; } void fft(cp *a,int o) { for (int i=0;i<n;i++) if (i>r[i]) swap(a[i],a[r[i]]); for (int i=1;i<n;i<<=1) for (int j=0;j<n;j+=(i*2)) for (int k=0;k<i;k++) { cp W=w[n/i*k]; W.y*=o; cp x=a[j+k],y=a[i+j+k]*W; a[j+k]=x+y; a[i+j+k]=x-y; } if (o==-1) rep(i,0,n-1) a[i].x/=n; } IL void get_cj(int *A,int *B,int len) { m=2*len; fft_init(); rep(i,0,len) a[i].x=A[i],b[i].x=B[i]; fft(a,1); fft(b,1); rep(i,0,n) a[i]=a[i]*b[i]; fft(a,-1); rep(i,0,m) B[i]=(int)(a[i].x+0.5); fft_clear(); } int main() { freopen("1.in","r",stdin); freopen("1.out","w",stdout); cin>>s; n=strlen(s); rep(i,1,n) t[i]=s[i-1]-'a',sum[i]=sum[i-1]+t[i]; jd[0]=1; rep(i,1,n) jd[i]=jd[i-1]*3; rep(i,1,n) hash1[i]=hash1[i-1]+(t[i]+1)*jd[i]; dep(i,n,1) hash2[i]=hash2[i+1]+(t[i]+1)*jd[n-i+1]; ll ans=0; rep(i,1,n) { int h=0,t=MIN(n-i,i-1); while(h<t) { if (check(i-mid,i,i,i+mid)) h=mid; else t=mid-1; } ans-=h+1; } rep(i,1,n-1) { int h=0,t=MIN(n-i,i)-1; while (h<t) { if (check(i-mid,i,i+1,i+1+mid)) h=mid; else t=mid-1; } if (check(i,i,i+1,i+1)) ans-=h+1; } rep(i,1,2*n) { if (i<=n) jl[i]=(i/2)-sum[i-1]; else jl[i]=((2*n-i+2)/2)-(sum[n]-sum[i-n-1]); if ((i&1)==0) jl[i]-=t[i/2]; } rep(i,0,n-1) A1[i]=t[i+1],B1[i]=t[i+1]; get_cj(A1,B1,n); dep(i,2*n,2) B1[i]=B1[i-2]; rep(i,1,2*n) if (i%2==0) B1[i]+=t[i/2]; rep(i,2,2*n) jl[i]+=B1[i]; rep(i,1,2*n) (ans+=fsp(2,jl[i])-1)%=mo; cout<<ans<<endl; return 0; }