題目鏈接
看到題面就不難想到是FFT的題
對兩個序列各開一個桶,分別爲A和B
當 時,不難想到把A反轉一下,然後把A和B做一個卷積就好了。
當 時,我們可以考慮cdq分治,合併區間把A在左區間的部分和B在右區間的部分做個卷積並累加就好了。
如果有誤在評論區吼一聲哦!
具體的話請看代碼:
#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;
const double pi=acos(-1.0);
int T,n,m,q,rev[200010],t1[50010],t2[50010];
struct cmplx{
double r,i;
cmplx(double a=0,double b=0){r=a;i=b;}
cmplx operator+(cmplx b){
return cmplx(r+b.r,i+b.i);
}
cmplx operator+=(cmplx b){
*this=*this+b;
return *this;
}
cmplx operator++(){
r++;
return *this;
}
cmplx operator-(cmplx b){
return cmplx(r-b.r,i-b.i);
}
cmplx operator*(cmplx b){
return cmplx(r*b.r-i*b.i,r*b.i+i*b.r);
}
cmplx operator*=(cmplx b){
*this=*this*b;
return *this;
}
}a[200010],b[200010],c[200010],x[200010],y[200010];
int rd(){
int x=0;
char c;
do c=getchar();
while(!isdigit(c));
do{
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}while(isdigit(c));
return x;
}
void FFT(cmplx *a,int limit,int type){
for(int i=0;i<limit;i++)
if(i<rev[i])
swap(a[i],a[rev[i]]);
for(int mid=1;mid<limit;mid<<=1){
cmplx wn=cmplx(cos(pi/mid),type*sin(pi/mid));
for(int i=0;i<limit;i+=(mid<<1)){
cmplx w=cmplx(1,0);
for(int j=0;j<mid;j++,w*=wn){
cmplx x=a[i+j],y=w*a[i+j+mid];
a[i+j]=x+y;
a[i+j+mid]=x-y;
}
}
}
if(type==-1)
for(int i=0;i<limit;i++)
a[i].r/=limit;
return;
}
void cdq(int l,int r){
if(l==r)
return;
int mid=(l+r)>>1;
cdq(l,mid);
cdq(mid+1,r);
int limit=1,len=0;
while(limit<=r-l+1){
limit<<=1;
len++;
}
for(int i=l;i<=mid;i++)
x[i-l]=t1[i];
for(int i=mid+1;i<=r;i++)
y[i-mid-1]=t2[i];
for(int i=mid-l+1;i<limit;i++)
x[i]=cmplx(0,0);
for(int i=r-mid;i<limit;i++)
y[i]=cmplx(0,0);
for(int i=0;i<limit;i++)
rev[i]=(rev[i>>1]>>1)|((i&1)<<(len-1));
FFT(x,limit,1);
FFT(y,limit,1);
for(int i=0;i<limit;i++)
x[i]*=y[i];
FFT(x,limit,-1);
for(int i=0;i<=r-l+1;i++)
c[i+l+mid+1]+=x[i];
return;
}
int main(){
scanf("%d",&T);
while(T--){
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(t1,0,sizeof(t1));
memset(t2,0,sizeof(t2));
n=rd();m=rd();q=rd();
for(int i=1;i<=n;i++){
int x=rd();
t1[x]++;
a[x]+=1;
}
for(int i=1;i<=m;i++){
int x=rd();
t2[x]+=1;
b[50000-x]+=1;
}
int limit=1,l=0;
while(limit<=100000){
limit<<=1;
l++;
}
for(int i=0;i<limit;i++)
rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
FFT(a,limit,1);
FFT(b,limit,1);
for(int i=0;i<limit;i++)
c[i]=a[i]*b[i];
FFT(c,limit,-1);
for(int i=0;i<=50000;i++)
c[i]=c[i+50000];
for(int i=50001;i<=100000;i++)
c[i]=0;
cdq(0,50000);
while(q--){
int ci=rd();
printf("%lld\n",(long long)(c[ci].r+0.5));
}
}
return 0;
}