LG P4199 万径人踪灭

Description

在只含a,b的字符串中,求满足以下条件的子序列个数:

  • 位置和字符关于某条对称轴对称
  • 不能是连续的一段

Solution

答案可以转化为关于某条对称轴对称的子序列-连续的回文串

连续的回文串可以用Manacher求出

关于某条对称轴对称的子序列可以FFT求出:将原字符串中为a的位置设为1,b的位置设为0,该多项式自平方后第$i$位即为以$\frac{i}{2}$为对称轴,左右两边相同位置为a的对数$x$,b同理,则分奇偶讨论可得以该对称轴为中心有$2^{x+1}-1$或$2^x-1$个字母组合满足条件

FFT多项式相乘

#include<iostream>
#include<cstring>
#include<complex>
#include<cstdio>
#include<cmath>
using namespace std;
long long len,rev[400005],tot=1,s=2,ans[400005],r[400005],sum;
const long long mod=1000000007;
const double pi=acos(-1);
char str[400005],sn[400005];
complex<double>an[400005],bn[400005];
inline long long read()
{
    long long w=0,f=1;
    char ch=0;
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        w=(w<<1)+(w<<3)+ch-'0';
        ch=getchar();
    }
    return w*f;
}
void fft(complex<double>*a,long long n,long long inv)
{
    for(long long i=0;i<n;i++)
    {
        if(i<rev[i])
        {
            swap(a[i],a[rev[i]]);
        }
    }
    for(long long i=1;i<n;i<<=1)
    {
        complex<double>wn=exp(complex<double>(0,inv*pi/i));
        for(long long j=0;j<n;j+=i*2)
        {
            complex<double>w(1,0);
            for(long long k=j;k<i+j;k++)
            {
                complex<double>x=a[k],y=w*a[k+i];
                a[k]=x+y;
                a[k+i]=x-y;
                w*=wn;
            }
        }
    }
    if(inv==-1)
    {
        for(long long i=0;i<n;i++)
        {
            a[i]/=n;
        }
    }
}
long long ksm(long long a,long long p)
{
    long long ret=1ll;
    while(p)
    {
        if(p&1)
        {
            (ret*=a)%=mod;
        }
        (a*=a)%=mod;
        p>>=1;
    }
    return ret;
}
void manacher()
{
    long long nlen=0,maxx=0,maxlen=-1,id;
    sn[nlen]='$';
    sn[++nlen]='#';
    for(long long i=0;i<len;i++)
    {
        sn[++nlen]=str[i];
        sn[++nlen]='#';
    }
    sn[++nlen]='\0';
    for(long long i=1;i<=nlen;i++)
    {
        if(i<maxx)
        {
            r[i]=min(r[2*id-i],maxx-i);
        }
        else
        {
            r[i]=1;
        }
        while(sn[i-r[i]]==sn[i+r[i]])
        {
            ++r[i];
        }
        if(maxx<i+r[i])
        {
            maxx=i+r[i];
            id=i;
        }
        ((sum-=(r[i]>>1))+=mod)%=mod;
    }
}
int main()
{
    scanf("%s",str);
    len=strlen(str);
    for(long long i=0;i<len;i++)
    {
        an[i]=(double)(str[i]=='a');
        bn[i]=(double)(str[i]=='b');
    }
    while((1<<tot)<(len<<1))
    {
        ++tot;
        s<<=1;
    }
    for(long long i=0;i<s;i++)
    {
        rev[i]=(rev[i>>1]>>1)|((i&1)<<(tot-1));
    }
    fft(an,s,1);
    fft(bn,s,1);
    for(long long i=0;i<s;i++)
    {
        an[i]*=an[i];
        bn[i]*=bn[i];
    }
    fft(an,s,-1);
    fft(bn,s,-1);
    for(long long i=0;i<s;i++)
    {
        ans[i]+=(long long)(an[i].real()+0.5);
        ans[i]+=(long long)(bn[i].real()+0.5);
        if(!(i&1))
        {
            ++ans[i];
        }
        ans[i]>>=1;
    }
    for(long long i=0;i<=2*len-2;i++)
    {
        ans[i]=ksm(2,ans[i])-1;
    }
    manacher();
    for(long long i=0;i<=2*len-2;i++)
    {
        (sum+=ans[i])%=mod;
    }
    printf("%lld\n",sum);
    return 0;
}
万径人踪灭

 

posted @ 2020-08-13 23:00  QDK_Storm  阅读(108)  评论(0编辑  收藏  举报