zoukankan      html  css  js  c++  java
  • BZOJ 3160 万径人踪灭 (FFT+manacher)

    题面: BZOJ传送门 洛谷传送门

    题目要求我们求一个序列的回文子序列数量

    可以用$FFT$搞定

    对于每种字符单独处理,以小写字母$a$为例

    把$a$所在的所有位置设为$1$,反之设为$0$

    卷积一下,会发现位置i卷出来的积就可能作为以$i/2$为中心的回文子序列的一个位置,设这个值为$x$

    那么以$i/2$为中心的回文子序列数量就是$2^x$

    然后题目还要求这种回文子序列不能是连续的,即不能是回文串

    用$manacher$去掉这部分不合法答案即可

    细节比较多

      1 #include <cmath>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 #define N1 (1<<18)+10
      6 #define M1 40010
      7 #define ll long long
      8 #define dd double
      9 #define inf 0x3f3f3f3f
     10 using namespace std;
     11  
     12 int gint()
     13 {
     14     int ret=0,fh=1;char c=getchar();
     15     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
     16     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
     17     return ret*fh;
     18 }
     19 const dd pi=acos(-1);
     20 const ll mod=1000000007;
     21 ll qpow(ll x,ll y)
     22 {
     23     ll ans=1;
     24     for(;y;x=x*x%mod,y>>=1)
     25         if(y&1) ans=ans*x%mod;
     26     return ans;
     27 }
     28 struct cp{
     29 dd x,y;
     30 friend cp operator + (const cp &s1,const cp &s2){ return (cp){s1.x+s2.x,s1.y+s2.y}; }
     31 friend cp operator - (const cp &s1,const cp &s2){ return (cp){s1.x-s2.x,s1.y-s2.y}; }
     32 friend cp operator * (const cp &s1,const cp &s2){ return (cp){s1.x*s2.x-s1.y*s2.y,s1.y*s2.x+s1.x*s2.y}; }
     33 }A[N1],B[N1],C[N1];
     34  
     35 void init()
     36 {
     37     memset(A,0,sizeof(A));
     38     memset(B,0,sizeof(B));
     39     memset(C,0,sizeof(C));
     40 }
     41  
     42 int r[N1];
     43 void FFT(cp *s,int len,int type)
     44 {
     45     int i,j,k;
     46     for(i=0;i<len;i++) if(i<r[i]) swap(s[i],s[r[i]]);
     47     for(k=2;k<=len;k<<=1)
     48     {
     49         cp wn=(cp){cos(2.0*pi*type/k),sin(2.0*pi*type/k)},w,t;
     50         for(i=0;i<len;i+=k)
     51         {
     52             w=(cp){1,0};
     53             for(j=0;j<(k>>1);j++,w=w*wn)
     54             {
     55                 t=w*s[i+j+(k>>1)];
     56                 s[i+j+(k>>1)]=s[i+j]-t;
     57                 s[i+j]=s[i+j]+t;
     58             }
     59         }
     60     }
     61 }
     62 void FFT_Main(int len)
     63 {
     64     FFT(A,len,1); FFT(B,len,1);
     65     for(int i=0;i<len;i++) C[i]=A[i]*B[i];
     66     FFT(C,len,-1);
     67     for(int i=0;i<len;i++) C[i].x/=len;
     68 }
     69  
     70 int n,m,len,L,f[N1];
     71 char str[N1],sstr[N1];
     72 ll ans[N1];
     73  
     74  
     75 int main()
     76 {
     77     scanf("%s",str); n=strlen(str);
     78     int i,mr,mid; ll ret=0,tmp=0;
     79     for(len=1,L=0;len<n+n;len<<=1,L++);
     80     for(i=0;i<len;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
     81      
     82     for(i=0;i<n;i++) A[i].x=(str[i]=='a'),B[i].x=(str[i]=='a');
     83     FFT_Main(len);
     84     for(i=0;i<n;i++) ans[i+2]+=((int)(C[i].x+0.1))/2;
     85      
     86     init();
     87     for(i=0;i<n;i++) A[i].x=(str[i]=='b'),B[i].x=(str[i]=='b');
     88     FFT_Main(len);
     89     for(i=0;i<n;i++) ans[i+2]+=((int)(C[i].x+0.1))/2;
     90      
     91     init();
     92     for(i=0;i<n;i++) A[i].x=(str[n-i-1]=='a'),B[i].x=(str[n-i-1]=='a');
     93     FFT_Main(len);
     94     for(i=0;i<n;i++) ans[2*n-i]+=((int)(C[i].x+0.1))/2;
     95      
     96     init();
     97     for(i=0;i<n;i++) A[i].x=(str[n-i-1]=='b'),B[i].x=(str[n-i-1]=='b');
     98     FFT_Main(len);
     99     for(i=0;i<n;i++) ans[2*n-i]+=((int)(C[i].x+0.1))/2;
    100      
    101     ans[n+1]/=2;
    102     mr=2,mid=1,f[1]=1;
    103     for(i=0,sstr[0]='$',sstr[1]='#';i<n;i++)
    104         sstr[(i+1)<<1]=str[i],sstr[(i+1)<<1|1]='#';
    105     for(i=2;i<=2*n+1;i++)
    106     {
    107         if(i<mr) f[i]=min(f[2*mid-i],mr-i);
    108         else f[i]=1;
    109         while(sstr[i-f[i]]==sstr[i+f[i]]) f[i]++;
    110         if(i+f[i]>mr)
    111             mr=i+f[i],mid=i;
    112     }
    113     for(i=1;i<=2*n+1;i++)
    114        ret=(ret+qpow(2,ans[i]+(!(i&1)))-1-(f[i]-(i&1))/2+mod)%mod;
    115     printf("%lld
    ",ret);
    116     return 0;
    117 }
  • 相关阅读:
    python多线程学习一
    https学习笔记三----OpenSSL生成root CA及签发证书
    https学习笔记二----基础密码学知识和python pycrypto库的介绍使用
    HTTPS学习笔记一----HTTPS的基础理论知识
    一只小鹅的2017
    python 全局变量的import机制
    一起来学设计模式-----工厂模式的实践
    一起来学设计模式-----创建型模式之抽象工厂
    一起来学设计模式-----创建型模式之工厂方法
    一起来学设计模式-----创建型模式之简单工厂
  • 原文地址:https://www.cnblogs.com/guapisolo/p/10321635.html
Copyright © 2011-2022 走看看