【BZOJ4836】[Lydsy2017年4月月赛]二元运算
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
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
0
1
0
0
1
0
1
0 1
题解:本题应该算是分治fft的比较好的入门题了。
按数的大小分治,将a中>mid的数与b中<=mid的数进行fft,将a中<=mid的数与b中>mid的数进行fft,然后递归处理下去即可。
#include <cstdio> #include <iostream> #include <cstring> #include <cmath> #define pi acos(-1.0) using namespace std; const int maxn=200010; typedef long long ll; struct cp { double x,y; cp () {} cp (double a,double b){x=a,y=b;} cp operator + (const cp &a) const {return cp(x+a.x,y+a.y);} cp operator - (const cp &a) const {return cp(x-a.x,y-a.y);} cp operator * (const cp &a) const {return cp(x*a.x-y*a.y,x*a.y+y*a.x);} }C[maxn],D[maxn]; int A[maxn],B[maxn]; ll ans[maxn]; int n,m,q,mx; void FFT(cp *a,int len,int f) { int i,j,k,h; cp t; for(i=k=0;i<len;i++) { if(i>k) swap(a[i],a[k]); for(j=len>>1;(k^=j)<j;j>>=1); } for(h=2;h<=len;h<<=1) { cp wn(cos(2*pi*f/h),sin(2*pi*f/h)); for(j=0;j<len;j+=h) { cp w(1,0); for(k=j;k<j+h/2;k++) t=a[k+h/2]*w,a[k+h/2]=a[k]-t,a[k]=a[k]+t,w=w*wn; } } } void solve(int l,int r) { if(l==r) { ans[0]+=(ll)A[l]*B[l]; return ; } int mid=(l+r)>>1,len,i; for(len=1;len<(r-l+1);len<<=1); memset(C,0,sizeof(C[0])*len),memset(D,0,sizeof(D[0])*len); for(i=l;i<=mid;i++) C[i-l].x=A[i]; for(i=mid+1;i<=r;i++) D[i-mid-1].x=B[i]; FFT(C,len,1),FFT(D,len,1); for(i=0;i<len;i++) C[i]=C[i]*D[i]; FFT(C,len,-1); for(i=0;i<len;i++) ans[i+l+mid+1]+=ll(C[i].x/len+0.1); memset(C,0,sizeof(C[0])*len),memset(D,0,sizeof(D[0])*len); for(i=mid+1;i<=r;i++) C[i-mid-1].x=A[i]; for(i=l;i<=mid;i++) D[mid-i].x=B[i]; FFT(C,len,1),FFT(D,len,1); for(i=0;i<len;i++) C[i]=C[i]*D[i]; FFT(C,len,-1); for(i=0;i<len;i++) ans[i+1]+=ll(C[i].x/len+0.1); solve(l,mid),solve(mid+1,r); } inline int rd() { int ret=0,f=1; char gc=getchar(); while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();} while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar(); return ret*f; } void work() { n=rd(),m=rd(),q=rd(); int i,a; mx=0,memset(A,0,sizeof(A)),memset(B,0,sizeof(B)),memset(ans,0,sizeof(ans)); for(i=1;i<=n;i++) a=rd(),A[a]++,mx=max(mx,a); for(i=1;i<=m;i++) a=rd(),B[a]++,mx=max(mx,a); solve(0,mx); for(i=1;i<=q;i++) a=rd(),printf("%lld ",ans[a]); } int main() { int T=rd(); while(T--) work(); return 0; }//2 2 1 5 1 3 2 1 2 3 4 5 2 2 5 1 3 2 4 1 2 3 4 5