您的位置:首页 > 其它

BZOJ 4836 二元运算

2018-01-30 19:04 155 查看

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的向量

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<complex>
using namespace std;
typedef long long lol;
const int NN=50005;
double pi=acos(-1.0);
struct data
{
double x,y;
};
data A[8*NN],B[8*NN];
int R[8*NN],n,n1,n2,m,N;
lol ans[8*NN],a[NN],b[NN];
data operator + (const data &a,const data &b){
return (data){a.x+b.x,a.y+b.y};
}
data operator - (const data &a,const data &b){
return (data){a.x-b.x,a.y-b.y};
}
data operator * (const data &a,const data &b){
return (data){a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x};
}
void FFT(data *D,int len,double o)
{int i,j,k;
for (i=0;i<len;i++)
if (i<R[i]) swap(D[i],D[R[i]]);
for (i=1;i<len;i<<=1)
{
data wn=(data){cos(pi/i),sin(o*pi/i)},x,y;
for (j=0;j<len;j+=(i<<1))
{
data w=(data){1,0};
for (k=0;k<i;k++,w=w*wn)
{
x=D[j+k];y=w*D[j+k+i];
D[j+k]=x+y;
D[j+k+i]=x-y;
}
}
}
}
void solve(int l,int r)
{int len,lg=0,i;
if (l==r)
return;
int mid=(l+r)/2;
len=1;
while (len<=r-l+1) len*=2,lg++;
for (i=0;i<len;i++)
R[i]=(R[i>>1]>>1)|((i&1)<<(lg-1));
for (i=0;i<len;i++)
A[i]=B[i]=(data){0,0};
for (i=l;i<=mid;i++)
A[i-l]=(data){a[i],0};
for (i=mid+1;i<=r;i++)
B[i-mid-1]=(data){b[i],0};
FFT(A,len,1);FFT(B,len,1);
for (i=0;i<len;i++)
A[i]=A[i]*B[i];
FFT(A,len,-1);
for (i=0;i<len;i++)
ans[i+l+mid+1]+=(lol)(A[i].x/len+0.5);
for (i=0;i<len;i++)
A[i]=B[i]=(data){0,0};
for (i=l;i<=mid;i++)
A[mid-i]=(data){b[i],0};
for (i=mid+1;i<=r;i++)
B[i-mid-1]=(data){a[i],0};
FFT(A,len,1);FFT(B,len,1);
for (i=0;i<len;i++)
A[i]=A[i]*B[i];
FFT(A,len,-1);
for (i=0;i<len;i++)
ans[i+1]+=(lol)(A[i].x/len+0.5);
solve(l,mid);solve(mid+1,r);
}
void work()
{int i,j,x,q;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
scanf("%d%d%d",&n,&m,&q);
for (i=1;i<=n;i++)
{
scanf("%d",&x);
a[x]++;
n1=max(n1,x);
}
for (i=1;i<=m;i++)
{
scanf("%d",&x);
b[x]++;
n2=max(n2,x);
}
memset(ans,0,sizeof(ans));
N=max(n1,n2);
for (i=1;i<=N;i++)
ans[0]+=a[i]*b[i];
solve(0,N);
for (i=1;i<=q;i++)
{
scanf("%d",&x);
printf("%lld\n",ans[x]);
}
}
int main()
{int T;
cin>>T;
while (T--)
work();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: