1. 程式人生 > >bzoj 4836: [Lydsy2017年4月月賽]二元運算 -- 分治+FFT

bzoj 4836: [Lydsy2017年4月月賽]二元運算 -- 分治+FFT

一行 -- fin -m pan swa blog 數據 spa

4836: [Lydsy2017年4月月賽]二元運算

Time Limit: 8 Sec Memory Limit: 128 MB

Description

定義二元運算 opt 滿足 技術分享 現在給定一個長為 n 的數列 a 和一個長為 m 的數列 b ,接下來有 q 次詢問。每次詢問給定一個數字 c 你需要求出有多少對 (i, j) 使得 a_i opt b_j=c 。

Input

第一行是一個整數 T (1≤T≤10) ,表示測試數據的組數。 對於每組測試數據: 第一行是三個整數 n,m,q (1≤n,m,q≤50000) 。 第二行是 n 個整數,表示 a_1,a_2,?,a_n (0≤a_1,a_2,?,a_n≤50000) 。 第三行是 m 個整數,表示 b_1,b_2,?,b_m (0≤b_1,b_2,?,b_m≤50000) 。 第四行是 q 個整數,第 i 個整數 c_i (0≤c_i≤100000) 表示第 i 次查詢的數。

Output

對於每次查詢,輸出一行,包含一個整數,表示滿足條件的 (i, j) 對的個數。

Sample Input

2
2 1 5
1 3
2
1 2 3 4 5
2 2 5
1 3
2 4
1 2 3 4 5

Sample Output

1
0
1
0
0
1
0
1
0
1

HINT

Source

可能我的常數真的巨大。。。

轉載一個姜大爺的題解 http://blog.csdn.net/neither_nor/article/details/70889246

#include<map>
#include<cmath>
#include
<queue> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define inf 1000000007 #define ll long long #define PI acos(-1) #define M 400010 inline int rd() { int x=0,f=1;char ch=getchar(); while(ch<0||ch>9){if
(ch==-)f=-1;ch=getchar();} while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();} return x*f; } #define db double struct cl{ db x,y; cl(){} cl(db _x,db _y){x=_x;y=_y;} friend cl operator +(const cl &x,const cl &y){return cl(x.x+y.x,x.y+y.y);} friend cl operator -(const cl &x,const cl &y){return cl(x.x-y.x,x.y-y.y);} friend cl operator *(const cl &x,const cl &y){return cl(x.x*y.x-x.y*y.y,x.x*y.y+x.y*y.x);} friend cl operator /(const cl &x,const db &y){return cl(x.x/y,x.y/y);} cl con(){return cl(x,-y);} }; cl a[M],b[M]; int n,L,R[M]; int A[M],B[M],mx,T; ll ans[M]; void fft(cl *x,int f,int n) { for(int i=0;i<n;i++) if(i<R[i]) swap(x[i],x[R[i]]); for(int i=1;i<n;i<<=1) { cl wn(cos(PI/i),f*sin(PI/i)); for(int j=0;j<n;j+=(i<<1)) { cl w(1,0),X,Y; for(int k=0;k<i;k++,w=w*wn) { X=x[j+k];Y=w*x[j+k+i]; x[j+k]=X+Y;x[j+k+i]=X-Y; } } } if(f==-1) for(int i=0;i<n;++i) x[i]=x[i]/n; } void cal(int l,int r,int n,int L) { if(l==r) { ans[0]+=(ll)A[l]*B[l]; return ; } register int i,j,mid=l+r>>1; for(i=0;i<n;++i) R[i]=(R[i>>1]>>1)|((i&1)<<L); for(i=0;i<n;++i) a[i]=b[i]=cl(0,0); for(i=l;i<=mid;++i) a[i-l].x=A[i]; for(i=mid+1;i<=r;++i) a[i-mid-1].y=B[i]; fft(a,1,n); for(i=0;i<n;i++) { j=(n-i)&(n-1); b[i]=(a[i]*a[i]-(a[j]*a[j]).con())*cl(0,-0.25); } fft(b,-1,n); for(i=0;i<n;++i) ans[l+mid+1+i]+=(ll)(b[i].x+0.1); for(i=0;i<n;++i) a[i]=b[i]=cl(0,0); for(i=mid+1;i<=r;i++) a[i-mid-1].x=A[i]; for(i=l;i<=mid;i++) a[mid-i].y=B[i]; fft(a,1,n); for(i=0;i<n;i++) { j=(n-i)&(n-1); b[i]=(a[i]*a[i]-(a[j]*a[j]).con())*cl(0,-0.25); } fft(b,-1,n); for(i=0;i<n;++i) ans[1+i]+=(ll)(b[i].x+0.1); cal(l,mid,n>>1,L-1); cal(mid+1,r,n>>1,L-1); } int main() { register int n1,n2,q,i,x; T=rd(); while(T--) { n1=rd();n2=rd();q=rd();mx=0; memset(A,0,sizeof(A)); memset(B,0,sizeof(B)); memset(ans,0,sizeof(ans)); for(i=0;i^n1;++i) { x=rd();A[x]++; mx=max(mx,x); } for(i=0;i^n2;i++) { x=rd();B[x]++; mx=max(mx,x); } for(n=1,L=-1;n<(mx<<1);n<<=1) L++; cal(0,n-1,n,L); while(q--) { x=rd(); printf("%lld\n",ans[x]); } } return 0; }

bzoj 4836: [Lydsy2017年4月月賽]二元運算 -- 分治+FFT