BZOJ3160: 万径人踪灭(FFT,回文自动机)

BZOJ传送门:

解题思路:

FFT在处理卷积时可以将自己与自己卷,在某一种字母上标1其他标0,做字符集次就好了。

(回文就是直接对称可以联系偶函数定义理解,根据这个性质就可以将字符串反向实现字符串匹配)。

最后利用容斥回文字符2的次幂-回文串就好了。

回文串计数当然要回文自动机了。

代码:

  1 #include<cmath>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 typedef long long lnt;
  6 const int maxn=362144;
  7 const double PI=acos(-1.0);
  8 const lnt mod=(lnt)(1e9+7);
  9 struct cp{
 10     double x,y;
 11     cp(){};
 12     cp(double a,double b){x=a,y=b;}
 13     cp friend operator + (cp a,cp b){return cp(a.x+b.x,a.y+b.y);}
 14     cp friend operator - (cp a,cp b){return cp(a.x-b.x,a.y-b.y);}
 15     cp friend operator * (cp a,cp b){return cp(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
 16 }A[maxn],B[maxn],C[maxn];
 17 struct PAM{
 18     struct pant{
 19         int tranc[2];
 20         int len;
 21         int pre;
 22         int wgt;
 23     }h[maxn];
 24     int siz;
 25     int fin;
 26     lnt ans;
 27     bool mis(char *a,int i,int lsp)
 28     {
 29         return a[i]!=a[i-h[lsp].len-1];
 30     }
 31     void Insert(char *a,int i)
 32     {
 33         int nwp,lsp,mac;
 34         lsp=fin;
 35         int c=a[i]-'a';
 36         while(mis(a,i,lsp))
 37             lsp=h[lsp].pre;
 38         if(!h[lsp].tranc[c])
 39         {
 40             nwp=++siz;
 41             mac=h[lsp].pre;
 42             h[nwp].len=h[lsp].len+2;
 43             while(mis(a,i,mac))
 44                 mac=h[mac].pre;
 45             h[nwp].pre=h[mac].tranc[c];
 46             h[lsp].tranc[c]=nwp;
 47             h[nwp].wgt=h[h[nwp].pre].wgt+1;
 48         }
 49         fin=h[lsp].tranc[c];
 50         ans+=h[fin].wgt;
 51         return ;
 52     }
 53     PAM(){}
 54     PAM(char *a,int n)
 55     {
 56         ans=0;
 57         siz=1;
 58         fin=0;
 59         h[1].pre=h[0].pre=1;
 60         h[1].len=-1;
 61         h[0].len=0;
 62         for(int i=1;i<=n;i++)
 63             Insert(a,i);
 64     }
 65     lnt val(void)
 66     {
 67         return ans;
 68     }
 69 };
 70 int lim;
 71 int len;
 72 int n,m;
 73 int pos[maxn];
 74 lnt pow2[maxn];
 75 char str[maxn];
 76 void getpos(void)
 77 {
 78     for(int i=0;i<len;i++)
 79         pos[i]=(pos[i>>1]>>1)|((i&1)<<(lim-1));
 80     return ;
 81 }
 82 void Fft(cp *a,double flag)
 83 {
 84     for(int i=0;i<len;i++)
 85         if(i<pos[i])
 86             std::swap(a[i],a[pos[i]]);
 87     for(int i=2;i<=len;i<<=1)
 88     {
 89         cp wn(cos(2.00*PI*flag/(double)(i)),sin(2.00*PI*flag/(double)(i)));
 90         for(int j=0;j<len;j+=i)
 91         {
 92             cp w(1.00,0.00),t;
 93             for(int k=0;k<(i>>1);k++,w=w*wn)
 94             {
 95                 t=a[k+j+(i>>1)]*w;
 96                 a[j+k+(i>>1)]=a[j+k]-t;
 97                 a[j+k]=a[j+k]+t;
 98             }
 99         }
100     }
101     return ;
102 }
103 int main()
104 {
105     scanf("%s",str+1);
106     int lth=strlen(str+1);
107     for(int i=1;i<=lth;i++)
108         if(str[i]=='a')
109             A[i-1].x=1.00;
110         else
111             B[i-1].x=1.00;
112     while((1<<lim)<(lth<<1))
113         lim++;
114     len=1<<lim;
115     getpos();
116     Fft(A,1);
117     Fft(B,1);
118     for(int i=0;i<len;i++)
119         A[i]=A[i]*A[i]+B[i]*B[i];
120     Fft(A,-1);
121     pow2[0]=1;
122     for(int i=1;i<=len;i++)
123         pow2[i]=pow2[i-1]*2ll%mod;
124     lnt ans=0;
125     for(int i=0;i<len;i++)
126         ans=(ans+pow2[((lnt)(A[i].x/(double)(len)+0.5)+1ll)/2]-1ll)%mod;
127     PAM P(str,lth);    
128         ans=((ans-P.val())%mod+mod)%mod;
129     printf("%lld
",ans);
130     return 0;
131 }   
原文地址:https://www.cnblogs.com/blog-Dr-J/p/10085150.html