Vexoben
Jul 15, 2018
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4836
(刷新以获取数学公式)
题解
不妨先考虑只有一种运算且没有取值范围的限制条件的时候。
令表示数组中的出现次数,同理,只需要计算:
则就是只有加法的答案,就是只有减法的答案。这是FFT模板题。
那么加上限制条件呢?分治FFT可以解决。
Solve(l,r)表示计算
答案可以分为四部分:
1、 这部分贡献全部是加法
2、 这部分贡献全部是减法
3、Solve(l,mid); 4、Solve(mid+1,r)
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=1<<17;
const double pi=acos(-1.0);
LL ans[N];
int n,m,q,a[N],b[N],rev[N];
struct C {
double r,i;
C(){}
C(double x,double y) {r=x,i=y;}
C operator + (C x) {return C(r+x.r,i+x.i);}
C operator - (C x) {return C(r-x.r,i-x.i);}
C operator * (C x) {return C(r*x.r-i*x.i,r*x.i+i*x.r);}
}A[N],B[N],w[N];
void FFT(C *a,int n) {
for (int i=0;i<n;i++)
if (i<rev[i]) swap(a[i],a[rev[i]]);
for (int t=n>>1,d=1;d<n;d<<=1,t>>=1) {
for (int i=0;i<n;i+=(d<<1)) {
for (int j=0;j<d;j++) {
C x=a[i+j],y=w[t*j]*a[i+j+d];
a[i+j]=x+y; a[i+j+d]=x-y;
}
}
}
}
void Solve(int l,int r) {
if (l==r) {
ans[0]+=1LL*a[l]*b[r];
return;
}
int mid=(l+r)>>1;
int n=mid-l,m=r-mid-1,limit=1,L=0;
while (limit<=n+m+2) limit<<=1,++L;
for (int i=0;i<limit;i++) {
w[i]=C(cos(2*i*pi/limit),sin(2*i*pi/limit));
rev[i]=(rev[i>>1]>>1)|((i&1)<<L-1);
}
for (int i=0;i<limit;i++) A[i]=B[i]=C(0,0);
for (int i=0;i<=n;i++) A[i]=C(a[i+l],0);
for (int i=0;i<=m;i++) B[i]=C(b[i+mid+1],0);
FFT(A,limit); FFT(B,limit);
for (int i=0;i<limit;i++) {
A[i]=A[i]*B[i];
w[i].i=-w[i].i;
}
FFT(A,limit);
for(int i=0;i<limit;i++) A[i].r/=limit;
for (int i=0;i<limit;i++) ans[i+l+mid+1]+=(LL)(A[i].r+0.5);
for (int i=0;i<limit;i++) A[i]=B[i]=C(0,0);
swap(n,m);
for (int i=0;i<=n;i++) A[i]=C(a[i+mid+1],0);
for (int i=0;i<=m;i++) B[m-i]=C(b[i+l],0);
FFT(A,limit); FFT(B,limit);
for (int i=0;i<limit;i++) {
A[i]=A[i]*B[i];
w[i].i=-w[i].i;
}
FFT(A,limit);
for (int i=0;i<limit;i++) A[i].r/=limit;
for (int i=0;i<limit;i++) ans[i+1]+=(LL)(A[i].r+0.5);
Solve(l,mid); Solve(mid+1,r);
}
void doit() {
scanf("%d%d%d",&n,&m,&q);
memset(ans,0,sizeof(ans));
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
for (int i=0;i<n;i++) {
int x; scanf("%d",&x); a[x]++;
}
for (int i=0;i<m;i++) {
int x; scanf("%d",&x); b[x]++;
}
Solve(0,50000);
while (q--) {
int x; scanf("%d",&x);
printf("%lld\n",ans[x]);
}
}
int main() {
int T; scanf("%d",&T);
while (T--) doit();
return 0;
}