[bzoj4836][分治FFT]二元运算

版权声明:蒻蒟的bolg... https://blog.csdn.net/Rose_max/article/details/85531959

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

题解

不考虑限制的话是个FFT裸题
大于的情况把B翻转一下取mx以上的就可以完美计数
单考虑小于怎么做
对值域分治
[ l , m i d ] [l,mid] [ m i d + 1 , r ] [mid+1,r] 这段区间中考虑B对A的贡献
显然把A在 [ l , m i d ] [l,mid] 和B在 [ m i d + 1 , r ] [mid+1,r] 中的数拿出来单独生成函数卷一下就可以了
分治做下去
还是挺裸的

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#include<set>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
using namespace std;
inline int read()
{
	int f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int stack[20];
inline void write(LL x)
{
	if(x<0){putchar('-');x=-x;}
    if(!x){putchar('0');return;}
    int top=0;
    while(x)stack[++top]=x%10,x/=10;
    while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(LL x){write(x);putchar('\n');}
const int MAXN=50005;
const double PI=acos(-1.0);
struct Complex
{
	double r,i;
	Complex(){}
	Complex(double _r,double _i){r=_r;i=_i;}
	friend Complex operator +(Complex u,Complex v){return Complex(u.r+v.r,u.i+v.i);}
	friend Complex operator -(Complex u,Complex v){return Complex(u.r-v.r,u.i-v.i);}
	friend Complex operator *(Complex u,Complex v){return Complex(u.r*v.r-u.i*v.i,u.r*v.i+u.i*v.r);}
}A[MAXN*4],B[MAXN*4];
int R[MAXN*4],L;
void fft(Complex *y,int len,int op)
{
	for(int i=0;i<len;i++)if(i<R[i])swap(y[i],y[R[i]]);
	for(int i=1;i<len;i<<=1)
	{
		Complex wn(cos(PI/i),sin(op*PI/i));
		for(int j=0;j<len;j+=(i<<1))
		{
			Complex w(1,0);
			for(int k=0;k<i;k++)
			{
				Complex u=y[j+k];
				Complex v=y[j+k+i]*w;
				y[j+k]=u+v;y[j+k+i]=u-v;
				w=w*wn;
			}
		}
	}
	if(op==-1)for(int i=0;i<len;i++)y[i].r/=len;
}
int vis1[MAXN],vis2[MAXN];
LL ans[10*MAXN];
void qry(int l,int r)
{
	if(l==r)return ;
	int mid=(l+r)/2;
	
	for(int i=l;i<=mid;i++)A[i-l]=Complex(vis1[i],0);
	for(int i=mid+1;i<=r;i++)B[i-(mid+1)]=Complex(vis2[i],0);
	L=0;int ln,l1=(mid-l+1),l2=(r-mid);
	for(ln=1;ln<=l1+l2;ln<<=1)L++;
	for(int i=0;i<ln;i++)R[i]=(R[i>>1]>>1)|(i&1)<<(L-1);
	fft(A,ln,1);fft(B,ln,1);
	for(int i=0;i<ln;i++)A[i]=A[i]*B[i];
	fft(A,ln,-1);
	for(int i=0;i<ln;i++)ans[i+l+mid+1]+=(LL)(A[i].r+0.5);
	for(int i=0;i<ln;i++)A[i]=B[i]=Complex(0,0);
	
	qry(l,mid);qry(mid+1,r);
}
int n,m,Q;
int main()
{
	int T=read();while(T--)
	{
		memset(ans,0,sizeof(ans));
		memset(vis1,0,sizeof(vis1));memset(vis2,0,sizeof(vis2));
		int mx=0;
		n=read();m=read();Q=read();
		for(int i=1;i<=n;i++)
		{
			int x=read();mx=max(mx,x);
			vis1[x]++;
		}
		for(int i=1;i<=m;i++)
		{
			int x=read();mx=max(mx,x);
			vis2[x]++;
		}
		int ln=0;L=0;
		for(ln=1;ln<=mx*2;ln<<=1)L++;R[0]=0;
		for(int i=0;i<ln;i++)R[i]=(R[i>>1]>>1)|(i&1)<<(L-1);
		for(int i=0;i<=mx;i++)A[i]=Complex(vis1[i],0);
		for(int i=0;i<=mx;i++)B[i]=Complex(vis2[mx-i],0);
		fft(A,ln,1);fft(B,ln,1);
		for(int i=0;i<ln;i++)A[i]=A[i]*B[i];
		fft(A,ln,-1);
		for(int i=mx;i<ln;i++)
			ans[i-mx]+=(LL)(A[i].r+0.5);
		for(int i=0;i<ln;i++)A[i]=B[i]=Complex(0,0);
		qry(0,mx);
		while(Q--)pr2(ans[read()]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Rose_max/article/details/85531959