zoukankan      html  css  js  c++  java
  • BZOJ4836 [Lydsy1704月赛]二元运算 分治 多项式 FFT

    原文链接http://www.cnblogs.com/zhouzhendong/p/8830036.html

    题目传送门 - BZOJ4836

    题意

      定义二元运算$opt$满足

    $$x opt y=egin{cases}x+y & ext{$(x<y)$} \ x-y & ext{$(xgeq y)$}end{cases}$$

      现在给定一个长为$n$的数列$a$和一个长为$m$的数列$b$,接下来有$q$次询问。每次询问给定一个数字$c$你需要求出有多少对$(i, j)$使得$a_i opt b_j=c$。

    题解

      这题看了标签差不多就是傻逼题QAQ。

      标签:分治+FFT

      好了题解就这么点QAQ。

      居然写了半个小时还好1A不然完蛋。

      $vdots$

      $vdots$

      $vdots$

      $vdots$

      $vdots$

      $vdots$

      $vdots$

      $vdots$

      $vdots$

      $vdots$

      $vdots$

      $vdots$

      $vdots$

      $vdots$

      $vdots$

      $vdots$

      $vdots$

      还是来正经点的吧。

      首先不考虑括号里的条件,假如分别针对两种运算$x+y$和$x-y$来写,该怎么办?

      $FFT$套路啊。

      我们对于$a$数组搞$50001$个桶,其中下标为$i$的桶保存到就是$a_x=i$的$x$个数。

      对于$b$也同理。

      假装$a_i$表示原先的$a$数组中$i$的个数,$b_i$同理。

      然后你要快速算$x+y$相同的,写下式子:

      $$h_i=sum_{j=0}^{i}a_jb_{i-j}$$

      显然可以$FFT$优化。

      然后你要算$x-y$相同的,你假装桶有负的下标,对于每一个$i$,使$b_{-i}=b_i$。

      然后让$b$整体向下标的正方向移动$50000$个单位(对于有效的前$50001$个,这个操作的效果就是将原来的$50001$个桶翻转),就可以列出和原来的那个差不多的式子,同样也可以$FFT$。

      但是原运算法则中有括号里面的条件啊。

      我们要强力满足这个条件。

      于是我们采用分治。

      对数值进行分治。

      我们分$3$类对最终答案进行贡献。

      假装我们把区间分成了$[L,mid]$和$(mid,R]$。

      $1.x=y$,只要再长度为$1$的区间内自己贡献一下就可以了。具体看代码。

      $2.x<y$,那我们只要让$a[L,mid]$和$b(mid,R]$按照原式的第一种运算方式算,并$FFT$优化即可。

      $3.x>y$,那我们只要让$a(mid,R]$和$b[l,mid]$按照原式的第二种运算方式算,并$FFT$优化即可。

      伪代码:

    solve(L,R)
        if (L=R)
            -->1.x=y
            return
        -->2.x<y
        -->3.x>y
        solve(L,mid),solve(mid+1,R)

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int N=1<<17;
    double PI=acos(-1.0);
    int read(){
    	int x=0;
    	char ch=getchar();
    	while (!('0'<=ch&&ch<='9'))
    		ch=getchar();
    	while ('0'<=ch&&ch<='9')
    		x=(x<<3)+(x<<1)+ch-48,ch=getchar();
    	return x;
    }
    int T,n,m,q,a[N],b[N];
    LL tot[N];
    int s,d,Rev[N];
    struct C{
    	double r,i;
    	C(){}
    	C(double a,double b){r=a,i=b;}
    	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);}
    }w[N],A[N],B[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 tmp=w[t*j]*a[i+j+d];
    				a[i+j+d]=a[i+j]-tmp;
    				a[i+j]=a[i+j]+tmp;
    			}
    }
    void solve(int L,int R){
    	if (L==R){
    		tot[0]+=1LL*a[L]*b[R];
    		return;
    	}
    	int mid=(L+R)>>1;
    	//a[L]...a[mid] VS b[mid+1]...b[R]
    	for (s=1,d=0;s<R-L;s<<=1,d++);
    	for (int i=0;i<s;i++){
    		Rev[i]=(Rev[i>>1]>>1)|((i&1)<<(d-1));
    		w[i]=C(cos(2*i*PI/s),sin(2*i*PI/s));
    		A[i]=B[i]=C(0,0);
    	}
    	for (int i=L;i<=mid;i++)
    		A[i-L]=C(a[i],0);
    	for (int i=mid+1;i<=R;i++)
    		B[i-mid-1]=C(b[i],0);
    	FFT(A,s),FFT(B,s);
    	for (int i=0;i<s;i++)
    		A[i]=A[i]*B[i],w[i].i*=-1.0;
    	FFT(A,s);
    	for (int i=0;i<R-L;i++)
    		tot[i+L+mid+1]+=(LL)(A[i].r/s+0.5);
    	//a[mid+1]...a[R] VS b[L]...b[mid]
    	for (int i=0;i<s;i++)
    		A[i]=B[i]=C(0,0),w[i].i*=-1.0;
    	for (int i=mid+1;i<=R;i++)
    		A[i-mid-1]=C(a[i],0);
    	for (int i=L;i<=mid;i++)
    		B[mid-i]=C(b[i],0);
    	FFT(A,s),FFT(B,s);
    	for (int i=0;i<s;i++)
    		A[i]=A[i]*B[i],w[i].i*=-1.0;
    	FFT(A,s);
    	for (int i=0;i<R-L;i++)
    		tot[i+mid+1-mid]+=(LL)(A[i].r/s+0.5);
    	solve(L,mid),solve(mid+1,R);
    }
    int main(){
    	T=read();
    	while (T--){
    		n=read(),m=read(),q=read();
    		memset(a,0,sizeof a);
    		memset(b,0,sizeof b);
    		while (n--)
    			a[read()]++;
    		while (m--)
    			b[read()]++;
    		memset(tot,0,sizeof tot);
    		solve(0,50000);
    		while (q--)
    			printf("%lld
    ",tot[read()]);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    HTTP状态码表
    统计各国访客插件 flag counter
    获取和设置cookie的方法(5种)
    最简单的方式创建node.js 静态服务器
    js中map,forEach,filter,reduce等方法是ECMAScript5 Array新增方法
    ECMAScript各个版本简介及特性
    JSON的parse()和stringfy()方法
    javascript中的错误对象error
    JS window对象的top、parent、opener含义介绍
    postman的使用总结
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ4836.html
Copyright © 2011-2022 走看看