您的位置:首页 > 其它

BZOJ3160: 万径人踪灭

2018-02-07 21:15 375 查看

n<=1e5的ab串,问对称的不连续的回文子序列数。取模。

虽然是道卷积题但是根本看不出来耶!

好吧没关系,要熟悉卷积那个图形:(红箭头那里是交于一点的,如果你觉得不是就是近视加深了)

1 #include<cstdio>
2 #include<cstdlib>
3 #include<algorithm>
4 #include<cstdlib>
5 #include<cstring>
6 #include<complex>
7 #include<math.h>
8 //#include<iostream>
9 using namespace std;
10
11 int n,m,wei;
12 #define maxn 262222
13 char s[maxn];
14 const double pi=acos(-1);
15 const int mod=1e9+7;
16 typedef complex<double> cp;
17 cp a[maxn],b[maxn],c[maxn];
18 int two[maxn],p[maxn],rev[maxn];
19
20 void dft(cp *a,int n,int type)
21 {
22     for (int i=0;i<n;i++) if (i<rev[i]) {cp t=a[i]; a[i]=a[rev[i]]; a[rev[i]]=t;}
23     for (int i=1;i<n;i<<=1)
24     {
25         cp base=cp(cos(pi/i),type*sin(pi/i));
26         for (int j=0,p=i<<1;j<n;j+=p)
27         {
28             cp t=cp(1,0);
29             for (int k=0;k<i;k++,t*=base)
30             {
31                 cp tmp=t*a[j+k+i];
32                 a[j+k+i]=a[j+k]-tmp;
33                 a[j+k]+=tmp;
34             }
35         }
36     }
37 }
38
39 void mul(cp *a,cp *b)
40 {
41     if (!rev[1]) for (int i=0;i<n;i++)
42     {
43         rev[i]=0;
44         for (int j=0;j<wei;j++) rev[i]|=((i>>j)&1)<<(wei-j-1);
45     }
46     dft(a,n,1);
47     for (int i=0;i<n;i++) b[i]=a[i]*a[i];
48     dft(b,n,-1);
49     for (int i=0;i<n;i++) b[i]/=n;
50 }
51
52 int main()
53 {
54     scanf("%s",s); n=strlen(s)-1;
55     m=n+n; for (n=1,wei=0;n<=m;n<<=1,wei++);
56     two[0]=1; for (int i=1;i<=m;i++) two[i]=(two[i-1]<<1)%mod;
57     m>>=1; for (int i=0;i<=m;i++) a[i]=(s[i]=='a'); m<<=1; mul(a,b);
58     m>>=1; for (int i=0;i<=m;i++) a[i]=(s[i]=='b');
59     for (int i=m+1;i<n;i++) a[i]=0; m<<=1; mul(a,c);
60     int ans=0;
61     for (int i=0;i<=m;i++) ans=(ans+two[((int)(b[i].real()+0.5)+(int)(c[i].real()+0.5)+1)>>1]-1)%mod;
62
63     m>>=1; n=m+1; s[n+n]='$'; s[n+n+1]='\0';
64     for (int i=n-1;i>=0;i--) s[i+i+1]=s[i],s[i+i]='$';
65     p[0]=1; int id=0;
66     for (int i=1,to=n+n;i<to;i++)
67     {
68         if (p[id]+id>i) p[i]=min(p[id+id-i],p[id]+id-i); else p[i]=1;
69         while (p[i]+i<=to && i-p[i]>=0 && s[p[i]+i]==s[i-p[i]]) p[i]++;
70         if (i+p[i]>id+p[id]) id=i;
71         ans=(ans-(p[i]>>1)+mod)%mod;
72     }
73     printf("%d\n",ans);
74     return 0;
75 }
View Code  

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: