BZOJ3160: 万径人踪灭
n<=1e5的ab串,问对称的不连续的回文子序列数。取模。
虽然是道卷积题但是根本看不出来耶!
好吧没关系,要熟悉卷积那个图形:(红箭头那里是交于一点的,如果你觉得不是就是近视加深了)
好来看这个题,要是连续的可以用manacher得,所以不连续条件可先排除掉。
然后剩下的东西不就是要求这种形式的东西有多少个嘛!
说人话,$f(i)$表示对称轴为$\frac{i}{2}$的有多少对(0.5表示对称轴为两个字母的中间),$p[i]=[s[i]==a]$
那么$f_i=\sum_{j=0}^{i}1-(p_j \ \ xor \ \ p_{i-j})$,好的,卷积!等等这不是积。。
异或的话,先设a为1,b为0,卷积算一次,再a为0,b为1,卷积算一次,加起来不久得了。。
一个$f_i$对答案贡献是$2^{\left \lceil \frac{f_i}{2} \right \rceil}-1$
OK
话说这题还挺有诗意的,看背景以为是恐怖故事,结果全文一直用一种轻快的笔调来描述题意,丝毫没有别离带来的惆怅。这让我想起旧时候的分别诗句:“海内存知己,天涯若比邻”,“莫愁前路无知己,天下谁人不识君”,而笔者竟对别离一笔带过,可谓是更胜一筹!在轻描淡写的别离时配以浓墨重彩的景物描写,别离之愁需如此美景才可释怀,万径依在,人踪已灭,不仅使得别离的苦闷更加浓厚,还表现了一种旷达的胸襟,妙哉!(本题分类:语文)
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 }