bzoj3160 万径人踪灭

版权声明:辣鸡蒟蒻的blog https://blog.csdn.net/elijahqi/article/details/79948588

http://www.elijahqi.win/archives/3096
题目在上方链接
Description

Input

Output

Sample Input

Sample Output

HINT

Source

2013湖北互测week1

首先将字符串中间插入”#” 把他们分隔开

题目要求求不连续的回文串的个数 那么就用总数减去连续的即可 考虑连续的部分 直接用manacher求即可 算出长度 然后再/2就是答案

不连续的怎么办 考虑现在用#将他们隔开 然后假如只考虑字符是a的贡献

那么 显然字符a都会出现在偶数位置上 那么想办法知道一个位置左右对称的符合要求的字符即可得到答案 比如#a#b#a这样关于b左右对称的就是2 然后答案就是2^2-1

那么想办法计算出左右对称位置符合要求的这个t即可

设当前在第k位

f[k]=i[kimod2=0][ski=a][sk+i=a] ti[ki=2×t][ski2=a][sk+i2=a] ti[ki=2×t]stskt t[k2t>=0]stskt t=0k2stskt s即表示该串这个位置是否为a|b为的话就是1

然后两次dft一次idft即可

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define pi acos(-1)
#define ll long long
using namespace std;
const int mod=1000000007;
const int N=100020;
struct C{
    double a,b;
    inline friend C operator +(const C &x,const C &y){return (C){x.a+y.a,x.b+y.b};}
    inline friend C operator -(const C &x,const C &y){return (C){x.a-y.a,x.b-y.b};}
    inline friend C operator *(const C &x,const C &y){return (C){x.a*y.a-x.b*y.b,x.a*y.b+x.b*y.a};}
    inline void operator *=(const C &y){*this=*this*y;}
}a[N<<2],b[N<<2];
int n,m,R[N<<2],p[N<<1];ll ans;
inline void fft(C *x,int f){
    for (int i=0;i<n;++i) if (i<R[i]) swap(x[i],x[R[i]]);
    for (int i=1;i<n;i<<=1){
        C wn=(C){cos(pi/i),f*sin(pi/i)};
        for (int j=0;j<n;j+=i<<1){
            C w=(C){1,0},t1,t2;
            for (int k=0;k<i;++k,w*=wn)
                t1=x[j+k],t2=x[j+k+i]*w,x[j+k]=t1+t2,x[j+k+i]=t1-t2;
        }
    }if (f==-1) for (int i=0;i<n;++i) x[i].a/=n;
}
inline int ksm(ll b,int t){static ll tmp;tmp=1;
    for (;t;b=b*b%mod,t>>=1) if (t&1) tmp=tmp*b%mod;return tmp;
}char s[N],s1[N<<1];
template<class T>
inline void add(T &x,int v){x=x+v>=mod?x+v-mod:x+v;}
template<class T>
inline void dec(T &x,int v){x=x-v<0?x-v+mod:x-v;}
int main(){
    freopen("bzoj3160.in","r",stdin);
    scanf("%s",s+1);m=strlen(s+1);m<<=1;
    int t=0;for (n=1;n<=m;n<<=1,++t);m>>=1;
    for (int i=0;i<n;++i) R[i]=(R[i>>1]>>1)|((i&1)<<t-1);
    for (int i=1;i<=m;++i) a[i].a=s[i]=='a',b[i].a=s[i]=='b';
    fft(a,1);
//  for (int i=0;i<n;++i) printf("%f\n",a[i].a);
    fft(b,1);for (int i=0;i<n;++i) a[i]=a[i]*a[i],b[i]=b[i]*b[i],a[i]=a[i]+b[i];
    fft(a,-1);for (int i=1;i<=m;++i) s1[i*2-1]='#',s1[i<<1]=s[i];m<<=1;int mx=0,id=0;
    for (int i=2;i<=m;++i) add(ans,ksm(2,((int)(a[i].a+0.1)+1>>1))-1);s1[++m]='#';
//  for (int i=1;i<=m;++i) printf("%lf\n",a[i].a);
//  for (int i=2;i<=m;++i) printf("%d\n",(int)(a[i].a+0.1)>>1);
    for (int i=1;i<=m;++i){
        if (i<mx) p[i]=min(mx-i,p[(id<<1)-i]);else p[i]=1;
        while(i-p[i]>0&&i+p[i]<=m&&s1[i-p[i]]==s1[i+p[i]]) ++p[i];
        if(i+p[i]>mx) mx=i+p[i],id=i;dec(ans,p[i]>>1);
    }
//  for (int i=1;i<=m;++i) printf("%d ",p[i]); 
    printf("%lld\n",ans);
    return 0;
}
阅读更多
想对作者说点什么?
相关热词

博主推荐

换一批

没有更多推荐了,返回首页