zoukankan      html  css  js  c++  java
  • 【BZOJ4836】[Lydsy2017年4月月赛]二元运算 分治+FFT

    【BZOJ4836】[Lydsy2017年4月月赛]二元运算

    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的比较好的入门题了。

    按数的大小分治,将a中>mid的数与b中<=mid的数进行fft,将a中<=mid的数与b中>mid的数进行fft,然后递归处理下去即可。

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <cmath>
    #define pi acos(-1.0)
    using namespace std;
    const int maxn=200010;
    typedef long long ll;
    struct cp
    {
    	double x,y;
    	cp () {}
    	cp (double a,double b){x=a,y=b;}
    	cp operator + (const cp &a) const {return cp(x+a.x,y+a.y);}
    	cp operator - (const cp &a) const {return cp(x-a.x,y-a.y);}
    	cp operator * (const cp &a) const {return cp(x*a.x-y*a.y,x*a.y+y*a.x);}
    }C[maxn],D[maxn];
    int A[maxn],B[maxn];
    ll ans[maxn];
    int n,m,q,mx;
    void FFT(cp *a,int len,int f)
    {
    	int i,j,k,h;
    	cp t;
    	for(i=k=0;i<len;i++)
    	{
    		if(i>k)	swap(a[i],a[k]);
    		for(j=len>>1;(k^=j)<j;j>>=1);
    	}
    	for(h=2;h<=len;h<<=1)
    	{
    		cp wn(cos(2*pi*f/h),sin(2*pi*f/h));
    		for(j=0;j<len;j+=h)
    		{
    			cp w(1,0);
    			for(k=j;k<j+h/2;k++)	t=a[k+h/2]*w,a[k+h/2]=a[k]-t,a[k]=a[k]+t,w=w*wn;
    		}
    	}
    }
    void solve(int l,int r)
    {
    	if(l==r)
    	{
    		ans[0]+=(ll)A[l]*B[l];
    		return ;
    	}
    	int mid=(l+r)>>1,len,i;
    	for(len=1;len<(r-l+1);len<<=1);
    	memset(C,0,sizeof(C[0])*len),memset(D,0,sizeof(D[0])*len);
    	for(i=l;i<=mid;i++)	C[i-l].x=A[i];
    	for(i=mid+1;i<=r;i++)	D[i-mid-1].x=B[i];
    	FFT(C,len,1),FFT(D,len,1);
    	for(i=0;i<len;i++)	C[i]=C[i]*D[i];
    	FFT(C,len,-1);
    	for(i=0;i<len;i++)	ans[i+l+mid+1]+=ll(C[i].x/len+0.1);
    	memset(C,0,sizeof(C[0])*len),memset(D,0,sizeof(D[0])*len);
    	for(i=mid+1;i<=r;i++)	C[i-mid-1].x=A[i];
    	for(i=l;i<=mid;i++)	D[mid-i].x=B[i];
    	FFT(C,len,1),FFT(D,len,1);
    	for(i=0;i<len;i++)	C[i]=C[i]*D[i];
    	FFT(C,len,-1);
    	for(i=0;i<len;i++)	ans[i+1]+=ll(C[i].x/len+0.1);
    	solve(l,mid),solve(mid+1,r);
    }
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    void work()
    {
    	n=rd(),m=rd(),q=rd();
    	int i,a;
    	mx=0,memset(A,0,sizeof(A)),memset(B,0,sizeof(B)),memset(ans,0,sizeof(ans));
    	for(i=1;i<=n;i++)	a=rd(),A[a]++,mx=max(mx,a);
    	for(i=1;i<=m;i++)	a=rd(),B[a]++,mx=max(mx,a);
    	solve(0,mx);
    	for(i=1;i<=q;i++)	a=rd(),printf("%lld
    ",ans[a]);
    }
    int main()
    {
    	int T=rd();
    	while(T--)	work();
    	return 0;
    }//2 2 1 5 1 3 2 1 2 3 4 5 2 2 5 1 3 2 4 1 2 3 4 5
  • 相关阅读:
    点到圆的切点
    两圆交点
    问n条平行于x,y的直线交点个数
    凸包与直线的关系
    Kuangbin的计算几何模板
    最大空凸包
    树链剖分模板题
    笔记1
    面试题2
    python utf-8 转码问题
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7434550.html
Copyright © 2011-2022 走看看