码迷,mamicode.com
首页 > 其他好文 > 详细

[bzoj3160]万径人踪灭

时间:2019-07-13 20:16:33      阅读:181      评论:0      收藏:0      [点我收藏+]

标签:bzoj   oid   register   bit   online   reg   size   href   int   

传送门

Description

技术图片

技术图片

Solution?

可以先求出所有满足条件\(1\)和条件\(2\)的子序列

然后减去其中不满足条件\(3\)的,也就是回文子串的数量

对于第一步,可以用\(NTT\)先求出每根对称轴有多少个位置与它对称,设为\(x\)
\[ x-a=b-x\\rightarrow a+b=2x \]
然后每个对称轴就有\(2^{x}-1\)的贡献

对于第二步,可以用manacher直接计算


Code?

/**************************************************************
    Problem: 3160
    User: PaperCloud
    Language: C++
    Result: Accepted
    Time:7748 ms
    Memory:15648 kb
****************************************************************/
 
#include<bits/stdc++.h>
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define reg register
#define ll long long
#define db double
#define int ll
#define PaperCloud FallDream
const int Mod=998244353,g=3,invg=332748118,P=1e9+7;
int Mul(int a,int b,int M=Mod){return (1ll*a*b)%M;}
int Add(int a,int b,int M=Mod){return (a+b)%M;}
int fpow(int a,int b,int M=Mod){int r=1;for(;b;b>>=1,a=Mul(a,a,M))if(b&1)r=Mul(r,a,M);return r;}
void NTT(int *a,int N,int ty,int *pos)
{
    int w,wn,i,j,p,k,X,Y;
    for(i=0;i<N;++i) if(pos[i]>i) std::swap(a[i],a[pos[i]]);
    for(i=1;i<N;i<<=1)
    {
        w=fpow(ty>0?g:invg,(Mod-1)/(i<<1));
        for(j=0,p=(i<<1);j<N;j+=p)
            for(wn=1,k=0;k<i;++k,wn=Mul(wn,w))
            {
                X=a[j+k],Y=Mul(a[j+i+k],wn);
                a[j+k]=Add(X,Y);a[j+i+k]=Add(X,Mod-Y);
            }
    }
    if(ty==-1)for(j=fpow(N,Mod-2),i=0;i<N;++i)a[i]=Mul(a[i],j);
}
const int MN=1e5+5;
char s[MN*3];
int a[2][MN*5],p[MN*3],ans,pos[MN*5];
int Calc(int len)
{
    s[len*2+1]='$';
    for(int i=len;i;--i) s[i*2]=s[i-1],s[i*2-1]='$';
    s[0]='*';
    int mx=0,id=0;
    for(int i=1;i<=(len<<1);++i)
    {
        p[i]=mx>i?min(p[id*2-i],mx-i):1;
        while(s[i+p[i]]==s[i-p[i]])++p[i];
        if(i+p[i]>mx)id=i,mx=p[i]+i;
    }
    ll r=0;
    for(int i=1;i<=(len<<1);++i) r=Add(r,p[i]/2,P);
    return r;
}
signed main()
{
    scanf("%s",s);
    int len=strlen(s);
    int N,i,j;
    for(N=1;N<len*2;N<<=1);
    memset(a,0,sizeof a);
    for(i=0;i<len;++i) a[s[i]=='b'][i]=1;
    for(i=0;i<N;++i) pos[i]=(pos[i>>1]>>1)|((i&1)*(N>>1));
//  for(i=0;i<len*2-1;++i) printf("%d : %d %d \n",i,a[0][i],a[1][i]);
    for(i=0;i<2;++i)
    {
        NTT(a[i],N,1,pos);
        for(j=0;j<N;++j) a[i][j]=Mul(a[i][j],a[i][j]);
        NTT(a[i],N,-1,pos);
    }
    for(i=0;i<len*2-1;++i) ans=Add(ans,Add(fpow(2,(a[0][i]+1)/2+(a[1][i]+1)/2,P),P-1,P),P);
//  printf("%d\n",ans);
    ans=Add(ans,P-Calc(len),P);
    return 0*printf("%lld\n",ans);
}



Blog来自PaperCloud,未经允许,请勿转载,TKS!

[bzoj3160]万径人踪灭

标签:bzoj   oid   register   bit   online   reg   size   href   int   

原文地址:https://www.cnblogs.com/PaperCloud/p/11181774.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!