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

Sample Output

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 }

 

posted @ 2018-01-30 19:04  Z-Y-Y-S  阅读(286)  评论(1编辑  收藏  举报