BZOJ 4836 二元运算
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
将数塞如一个桶,a[i]表示a中i这个数有多少个,b同样
如果a[1]=2,b[3]=3,那么ans[4]+=a[1]*b[3]
发现加法通过构造形成了卷积,减法通过反转也是卷积
因为分两种情况,不能直接卷积
分治时,考虑[l,mid]的数opt [mid+1,r]的数产生的答案
用两个FFT解决
此题卡常,不要用STL的向量
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #include<complex> 7 using namespace std; 8 typedef long long lol; 9 const int NN=50005; 10 double pi=acos(-1.0); 11 struct data 12 { 13 double x,y; 14 }; 15 data A[8*NN],B[8*NN]; 16 int R[8*NN],n,n1,n2,m,N; 17 lol ans[8*NN],a[NN],b[NN]; 18 data operator + (const data &a,const data &b){ 19 return (data){a.x+b.x,a.y+b.y}; 20 } 21 data operator - (const data &a,const data &b){ 22 return (data){a.x-b.x,a.y-b.y}; 23 } 24 data operator * (const data &a,const data &b){ 25 return (data){a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x}; 26 } 27 void FFT(data *D,int len,double o) 28 {int i,j,k; 29 for (i=0;i<len;i++) 30 if (i<R[i]) swap(D[i],D[R[i]]); 31 for (i=1;i<len;i<<=1) 32 { 33 data wn=(data){cos(pi/i),sin(o*pi/i)},x,y; 34 for (j=0;j<len;j+=(i<<1)) 35 { 36 data w=(data){1,0}; 37 for (k=0;k<i;k++,w=w*wn) 38 { 39 x=D[j+k];y=w*D[j+k+i]; 40 D[j+k]=x+y; 41 D[j+k+i]=x-y; 42 } 43 } 44 } 45 } 46 void solve(int l,int r) 47 {int len,lg=0,i; 48 if (l==r) 49 return; 50 int mid=(l+r)/2; 51 len=1; 52 while (len<=r-l+1) len*=2,lg++; 53 for (i=0;i<len;i++) 54 R[i]=(R[i>>1]>>1)|((i&1)<<(lg-1)); 55 for (i=0;i<len;i++) 56 A[i]=B[i]=(data){0,0}; 57 for (i=l;i<=mid;i++) 58 A[i-l]=(data){a[i],0}; 59 for (i=mid+1;i<=r;i++) 60 B[i-mid-1]=(data){b[i],0}; 61 FFT(A,len,1);FFT(B,len,1); 62 for (i=0;i<len;i++) 63 A[i]=A[i]*B[i]; 64 FFT(A,len,-1); 65 for (i=0;i<len;i++) 66 ans[i+l+mid+1]+=(lol)(A[i].x/len+0.5); 67 for (i=0;i<len;i++) 68 A[i]=B[i]=(data){0,0}; 69 for (i=l;i<=mid;i++) 70 A[mid-i]=(data){b[i],0}; 71 for (i=mid+1;i<=r;i++) 72 B[i-mid-1]=(data){a[i],0}; 73 FFT(A,len,1);FFT(B,len,1); 74 for (i=0;i<len;i++) 75 A[i]=A[i]*B[i]; 76 FFT(A,len,-1); 77 for (i=0;i<len;i++) 78 ans[i+1]+=(lol)(A[i].x/len+0.5); 79 solve(l,mid);solve(mid+1,r); 80 } 81 void work() 82 {int i,j,x,q; 83 memset(a,0,sizeof(a)); 84 memset(b,0,sizeof(b)); 85 scanf("%d%d%d",&n,&m,&q); 86 for (i=1;i<=n;i++) 87 { 88 scanf("%d",&x); 89 a[x]++; 90 n1=max(n1,x); 91 } 92 for (i=1;i<=m;i++) 93 { 94 scanf("%d",&x); 95 b[x]++; 96 n2=max(n2,x); 97 } 98 memset(ans,0,sizeof(ans)); 99 N=max(n1,n2); 100 for (i=1;i<=N;i++) 101 ans[0]+=a[i]*b[i]; 102 solve(0,N); 103 for (i=1;i<=q;i++) 104 { 105 scanf("%d",&x); 106 printf("%lld\n",ans[x]); 107 } 108 } 109 int main() 110 {int T; 111 cin>>T; 112 while (T--) 113 work(); 114 }