BZOJ3160:万径人踪灭
Description
Input & Output & Sample Input & Sample Output
HINT
题解:
题意即求不连续但间隔长度对称的回文串个数。
若si=sj,则这对字符可以作为以(i+j)/2为中心的回文串的一部分。
用F[i]来表示可以做为以i/2为中心的回文串的一部分的字符对数,则以i/2为中心的回文串数为2^F[i]。
则这就成了多项式乘法:先做一次a的,把字符为a的位置值赋为1,其余为0,进行一次FFT;同理做一次b的。
因为完全连续是不可以的,所以用Manacher求出这样的回文串的个数并减去。
代码:
(BZOJ上PASCAL跑得不够快,再加上这题时限只有10s,并没有AC,不知道那些用PASCAL通过的人是怎么卡常数的)
1 uses math; 2 const 3 mo=1000000007; 4 type 5 xs=record 6 x,y:double; 7 end; 8 arr=array[0..270001]of xs; 9 var 10 e,t:arr; 11 a:array[1..5]of arr; 12 n,m,i,ll,ans:longint; 13 ch:array[-2..270001]of char; 14 b:array[-2..270001]of longint; 15 z,ksm:array[0..270001]of longint; 16 s:ansistring; 17 operator -(a,b:xs)c:xs; 18 begin c.x:=a.x-b.x; c.y:=a.y-b.y; end; 19 operator +(a,b:xs)c:xs; 20 begin c.x:=a.x+b.x; c.y:=a.y+b.y; end; 21 operator *(a,b:xs)c:xs; 22 begin c.x:=a.x*b.x-a.y*b.y; c.y:=a.x*b.y+a.y*b.x; end; 23 procedure manacher; 24 var k,l,i:longint; 25 begin 26 k:=-1; l:=-1; b[-1]:=1; 27 for i:=0 to m*2-1 do 28 begin 29 if l>=i then 30 b[i]:=min(b[2*k-i],l-i+1)else b[i]:=1; 31 while true do 32 begin 33 if ch[i+b[i]]=ch[i-b[i]] then inc(b[i]) 34 else break; 35 end; 36 ans:=(ans+mo-(b[i]shr 1))mod mo; 37 if i+b[i]-1>l then begin l:=i+b[i]-1; k:=i; end; 38 end; 39 end; 40 procedure fft(xx:longint); 41 var i,j,q,k,l,c:longint; 42 t:xs; 43 begin 44 for i:=0 to n-1 do a[xx+2,z[i]]:=a[xx,i]; 45 xx:=xx+2; 46 k:=n; l:=1; 47 for i:=ll downto 1 do 48 begin 49 k:=k shr 1; 50 for j:=0 to k-1 do 51 begin 52 c:=j*2*l; 53 for q:=0 to l-1 do 54 begin 55 t:=e[q*k]*a[xx,c+l]; 56 a[xx,c+l]:=a[xx,c]-t; 57 a[xx,c]:=a[xx,c]+t; 58 inc(c); 59 end; 60 end; 61 l:=l*2; 62 end; 63 end; 64 begin 65 readln(s); m:=length(s); 66 ch[-2]:='+'; 67 for i:=0 to m-1 do ch[i*2]:=s[i+1]; 68 ch[m*2+1]:='-'; 69 manacher; 70 for i:=0 to m-1 do if ch[i*2]='a' then a[1,i].x:=1; 71 for i:=0 to m-1 do if ch[i*2]='b' then a[2,i].x:=1; 72 n:=1; 73 while n<m*2 do begin n:=n*2; inc(ll); end; 74 for i:=1 to n-1 do z[i]:=(z[i shr 1]shr 1)or((i and 1)shl(ll-1)); 75 ksm[0]:=1; for i:=1 to 100000 do ksm[i]:=(ksm[i-1]*2)mod mo; 76 for i:=0 to n-1 do e[i].x:=cos(pi*2*i/n); 77 for i:=0 to n-1 do e[i].y:=sin(pi*2*i/n); 78 fft(1); fft(2); 79 for i:=0 to n-1 do a[3,i]:=a[3,i]*a[3,i]+a[4,i]*a[4,i]; 80 for i:=0 to n-1 do e[i].y:=-e[i].y; 81 fft(3); 82 for i:=0 to m-1 do a[5,i*2].x:=a[5,i*2].x+n; 83 for i:=0 to n-1 do ans:=(ans+ksm[round(a[5,i].x/2/n)]-1)mod mo; 84 writeln(ans); 85 end.
1 #include<bits/stdc++.h> 2 using namespace std; 3 int mo=1000000007; 4 typedef pair<double,double> pa; 5 pa operator + (pa a,pa b) 6 { pa c; c.first=a.first+b.first; c.second=a.second+b.second; return c; } 7 pa operator - (pa a,pa b) 8 { pa c; c.first=a.first-b.first; c.second=a.second-b.second; return c; } 9 pa operator * (pa a,pa b) 10 { pa c; c.first=a.first*b.first-a.second*b.second; c.second=a.first*b.second+a.second*b.first; return c; } 11 pa a[5][270005],e[270005]; 12 char s[270005],s2[270005]; 13 int n,ans,nn,m,ksm[270005],z[270005]; 14 void manacher() 15 { 16 int l=1,k=1; z[1]=0; 17 for(int i=2;i<=nn;i++) 18 { 19 if(l>=i)z[i]=min(z[2*k-i],l-i);else z[i]=0; 20 while(s2[i+z[i]+1]==s2[i-z[i]-1])z[i]++; 21 ans=(ans-(z[i]+1)/2)%mo; if(i+z[i]>l){ k=i; l=i+z[i]; } 22 } 23 } 24 void fft(int x) 25 { 26 for(int i=0;i<m;i++)a[x+1][z[i]]=a[x][i]; x++; 27 for(int k=m/2,i=1;i<m;i*=2,k/=2) for(int j=0;j<m;j+=2*i) for(int l=0;l<i;l++) 28 { pa t=e[k*l]*a[x][j+l+i]; a[x][j+l+i]=a[x][j+l]-t; a[x][j+l]=a[x][j+l]+t; } 29 } 30 int main() 31 { 32 scanf("%s",s+1); n=strlen(s+1); nn=1; s2[0]='!'; s2[1]='*'; 33 for(int i=1;i<=n;i++){ nn++; s2[nn]=s[i]; nn++; s2[nn]='*'; } s2[nn+1]='?'; 34 manacher(); 35 ksm[0]=1; for(int i=1;i<=270000;i++)ksm[i]=ksm[i-1]*2%mo; 36 m=1; while(m<2*n)m=m*2; 37 for(int i=1;i<m;i++)z[i]=(z[i>>1]>>1)+(i&1)*m/2; 38 e[0].first=1; e[1].first=cos(2*acos(-1)/m); e[1].second=sin(2*acos(-1)/m); 39 for(int i=2;i<m;i++)e[i]=e[i-1]*e[1]; 40 for(int i=1;i<=n;i++)if(s[i]=='a')a[0][i-1].first=1; fft(0); 41 for(int i=1;i<=n;i++)if(s[i]=='b')a[2][i-1].first=1; fft(2); 42 for(int i=0;i<m;i++)a[3][i]=a[1][i]*a[1][i]+a[3][i]*a[3][i]; 43 for(int i=0;i<m;i++)e[i].second=-e[i].second; 44 fft(3); 45 for(int i=0;i<m;i++)ans=(ans+ksm[((int)round(a[4][i].first/m)+1)/2]-1)%mo; 46 ans=(ans+mo)%mo; 47 printf("%d\n",ans); 48 }