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;
}

 

posted @ 2018-12-11 20:49  尹吴潇  阅读(178)  评论(0编辑  收藏  举报