zoukankan      html  css  js  c++  java
  • Luogu P4199 万径人踪灭

    我们把所有相同的字符对的贡献求出来,减去回文子串的个数,就是最后的答案。

    求每个回文中心的相同字母对个数 (f[i]) ,我们可以用卷积去求。贡献是 (2^{f[i]/2+[i\%2==0]-1})([i\%2==0]) 表示位置在 (frac{i}{2}) 的字符仅会被记一次,(/2) 时会除掉,所以我们要加上。

    回文子串个数可以用 (PAM) 求。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #define R register int
    #define ll long long
    using namespace std;
    namespace Luitaryi {
    inline int g() { R x=0,f=1;
      register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
      do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
    } const int N=400010,M=1000000007;
    const double PI=acos(-1.0);
    int n,p[N],K,len,f[N],ans;
    char s[N];
    struct ci {
      double x,y;
      inline ci operator + (const ci& that) const 
        {return (ci){x+that.x,y+that.y};}
      inline ci operator - (const ci& that) const 
        {return (ci){x-that.x,y-that.y};}
      inline ci operator * (const ci& that) const 
        {return (ci){x*that.x-y*that.y,x*that.y+y*that.x};}
    }a[N];
    inline void fft(ci* a,int op) {
      for(R i=0;i<K;++i) if(i<p[i]) swap(a[i],a[p[i]]);
      for(R l=1;l<K;l<<=1) {
        register ci w1=(ci){cos(PI/l),op*sin(PI/l)},wn,x,y;
        for(R len=l<<1,i=0;i<K;i+=len) {
          wn=(ci){1,0};
          for(R j=0;j<l;++j,wn=wn*w1)
            x=a[i+j],y=wn*a[i+j+l],a[i+j]=x+y,a[i+j+l]=x-y;
        }
      }
    }
    struct PAM {
      int lst,tot,fa[N],len[N],c[N][26],sz[N]; ll ans;
      inline void init() {len[fa[0]=tot=1]=-1;}
      inline int jmp(int p,int i) 
        {while(s[i-len[p]-1]!=s[i]) p=fa[p]; return p;}
      inline void ext(int ch,int i) {
        R p=jmp(lst,i); if(!c[p][ch]) {
          R np=++tot; len[np]=len[p]+2;
          R t=jmp(fa[p],i); 
          fa[np]=c[t][ch],c[p][ch]=np;
        } ++sz[lst=c[p][ch]];
      }
      inline void cal() {
        for(R i=tot;i>=2;--i)   
          sz[fa[i]]+=sz[i],ans+=sz[i];
      }
    }p1;
    inline int qpow(int a,int b) { R ret=1;
      for(;b;b>>=1,a=1ll*a*a%M) if(b&1) ret=1ll*ret*a%M; return ret;
    }
    inline void main() {
      scanf("%s",s+1),n=strlen(s+1),p1.init();
      for(R i=1;i<=n;++i) p1.ext(s[i]-'a',i);
      K=1; while(K<=2*n) K<<=1,++len;
      for(R i=0;i<K;++i) p[i]=(p[i>>1]>>1)|((i&1)<<(len-1));
      for(R i=1;i<=n;++i) a[i].x=s[i]=='a',a[i].y=0;
      fft(a,1); for(R i=0;i<K;++i) a[i]=a[i]*a[i]; 
      fft(a,-1); for(R i=0;i<K;++i) f[i]=(f[i]+(int)(a[i].x/K+0.5))%M;
      memset(a,0,sizeof a);
      for(R i=1;i<=n;++i) a[i].x=s[i]=='b',a[i].y=0;
      fft(a,1); for(R i=0;i<K;++i) a[i]=a[i]*a[i]; 
      fft(a,-1); for(R i=0;i<K;++i) f[i]=(f[i]+(int)(a[i].x/K+0.5))%M;
      p1.cal(); ans=-p1.ans%M; 
      for(R i=1;i<=2*n;++i) ans=(ans+qpow(2,f[i]/2+((i&1)^1))-1)%M;
      printf("%d
    ",(ans+M)%M); 
    }
    } signed main() {Luitaryi::main(); return 0;}
    

    2020.01.16

  • 相关阅读:
    2018 eclipse安装反编译插件
    Buffer flip()方法
    区块链2
    Mist 转移默认区块存储位置方法
    区块链1
    如何在Ubuntu下安装”.deb“、”.bin“、”.tar.gz“、”.tar.bz2“格式的软件包!
    eclipse 性能调优之内存分配
    linux中搭建java开发环境
    在 Ubuntu 14.04 上安装 Ubuntu Tweak 0.8.8
    Ubuntu各个版本的介绍
  • 原文地址:https://www.cnblogs.com/Jackpei/p/12203188.html
Copyright © 2011-2022 走看看