洛咕 P4199 万径人踪灭

给了两条限制,但是第二条想想是没用的,直接manacher就可以减掉多余的部分了,所以要求满足第一条的方案

也不难,可以想到枚举每个中心点,计算两边有多少对距离中心相等的位置值也相等,假设有\(t\)个,那么以这个中心点为半径的就是\(2^t-1\),因为每个都可以选或不选,减去全都不选的情况

现在就要计算和每个中心点距离相等的位置对数了,显然两个位置\(a,b\)如果值相同,那么中心就是\((a+b)/2\)(如果是小数的话就是两个格子之间的)

所以就简单了,\(A(i)=[S[i]='a'],B(i)=[S[i]='b']\),这两个多项式分别平方一下,然后再算\(2^x-1\),所有这些之和就是满足第一条的方案了

#include<bits/stdc++.h>
#define il inline
#define vd void
#define mod 1000000007
typedef long long ll;
il int gi(){
    int x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return x*f;
}
const double pi=acos(-1);
struct cp{
    double real,imag;
    cp(){}
    cp(const double&r,const double&i){real=r,imag=i;}
    il cp conj(){return(cp){real,-imag};}
    il vd operator =(const double&b){real=b,imag=0;}
};
il cp operator +(const cp&a,const cp&b){return(cp){a.real+b.real,a.imag+b.imag};}
il cp operator -(const cp&a,const cp&b){return(cp){a.real-b.real,a.imag-b.imag};}
il cp operator *(const cp&a,const cp&b){return(cp){a.real*b.real-a.imag*b.imag,a.real*b.imag+a.imag*b.real};}
char S[200010];
int rev[1<<19];
cp A[1<<19],omg[1<<19],inv[1<<19];
il vd fft(cp*A,int n,cp*omg){
    for(int i=0;i<n;++i)if(rev[i]>i)std::swap(A[i],A[rev[i]]);
    for(int o=1;o<n;o<<=1)
        for(cp*p=A;p!=A+n;p+=o<<1)
            for(int i=0;i<o;++i){
                cp t=omg[n/(o<<1)*i]*p[i+o];
                p[i+o]=p[i]-t,p[i]=p[i]+t;
            }
}
int t[200010];
il int pow(int x,int y){
    int ret=1;
    while(y){
        if(y&1)ret=1ll*ret*x%mod;
        x=1ll*x*x%mod;y>>=1;
    }
    return ret;
}
int r[200010];
int main(){
    scanf("%s",S+1);int n=strlen(S+1);
    int N=1,lg=0;while(N<(n+2)<<1)N<<=1,++lg;
    for(int i=0;i<N;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<lg-1);
    for(int i=0;i<N;++i)omg[i]=cp(cos(i*2*pi/N),sin(i*2*pi/N)),inv[i]=omg[i].conj();
    for(int i=1;i<=n;++i)A[i]=S[i]=='a';
    fft(A,N,omg);
    for(int i=0;i<N;++i)A[i]=A[i]*A[i];
    fft(A,N,inv);
    for(int i=1;i<=n<<1;++i)t[i]=(int)(A[i].real/N+0.5);
    for(int i=0;i<N;++i)A[i]=0;
    for(int i=1;i<=n;++i)A[i]=S[i]=='b';
    fft(A,N,omg);
    for(int i=0;i<N;++i)A[i]=A[i]*A[i];
    fft(A,N,inv);
    for(int i=1;i<=n<<1;++i)t[i]+=(int)(A[i].real/N+0.5);
    ll ans=0;
    for(int i=1;i<=n<<1;++i)t[i]=t[i]/2+!(i&1),ans+=pow(2,t[i])-1;
    for(int i=n;i;--i)S[i<<1]=S[i];
    N=n<<1|1;
    for(int i=1;i<=N;i+=2)S[i]='#';
    S[0]='s',S[N+1]='t';
    int R=1,mid=1;r[1]=1;
    for(int i=2;i<=N;++i){
        r[i]=1;
        if(i<=R)r[i]=std::min(R-i+1,r[mid*2-i]);
        while(S[i-r[i]]==S[i+r[i]])++r[i];
        if(i+r[i]-1>R)mid=i,R=i+r[i]-1;
    }
    for(int i=1;i<=N;++i)ans-=r[i]>>1;
    printf("%lld\n",(ans%mod+mod)%mod);
    return 0;
}
posted @ 2018-12-03 20:29  菜狗xzz  阅读(197)  评论(0编辑  收藏  举报