BSOJ2091题解

这题好厉害。。。记录一下。

先把 \(a\)\(b\) 丢到桶里面。

你需要考虑上面所有位置对下面所有位置的贡献,最简单的方法是前缀和,但是由于贡献是多项式所以会寄。

考虑分治。(完全想不到.jpg)

在值域上进行分治,然后显然有 \(O(n\log^2n)\)。。。

#include<cstdio>
#include<cctype>
#include<cmath>
#define IMP(lim,act) for(int qwq=(lim),i=0;i^qwq;++i)act
typedef double db;
const int M=1<<18;const db Pi=acos(-1);
int T,n,m,q,a[M],b[M];long long ans[M];
inline int Getlen(const int&n){
	int len(0);while((1<<len)<n)++len;return len;
}
struct complex{
	db x,y;
	complex(const db&x=0,const db&y=0):x(x),y(y){}
	inline complex operator+(const complex&it)const{
		return complex(x+it.x,y+it.y);
	}
	inline complex operator-(const complex&it)const{
		return complex(x-it.x,y-it.y);
	}
	inline complex operator*(const complex&it)const{
		return complex(x*it.x-y*it.y,x*it.y+y*it.x);
	}
}buf[M<<2],*w[20],f[M];
inline void swap(complex&a,complex&b){
	complex c=a;a=b;b=c;
}
inline void init(const int&n){
	int m=Getlen(n);complex*now=buf;w[m]=now;now+=1<<m;
	for(int i=0;i^1<<m;++i)w[m][i]=complex(std::cos(1.*i/(1<<m)*Pi),std::sin(1.*i/(1<<m)*Pi));
	for(int k=m-1;k>=0&&(w[k]=now,now+=1<<k);--k)IMP(1<<k,w[k][i]=w[k+1][i<<1]);
}
inline void DFT(complex*f,const int&M){
	const int&n=1<<M;
	for(int len=n>>1,d=M-1;d>=0;--d,len>>=1){
		for(int k=0;k^n;k+=len<<1){
			complex*W=w[d],*L=f+(k),*R=f+(k|len),x,y;IMP(len,(x=*L,y=*R)),*L++=(x+y),*R++=*W++*(x-y);
		}
	}
}
inline void IDFT(complex*f,const int&M){
	const int&n=1<<M;
	for(int len=1,d=0;d<M;++d,len<<=1){
		for(int k=0;k^n;k+=len<<1){
			complex*W=w[d],*L=f+(k),*R=f+(k|len),x,y;IMP(len,(x=*L,y=*W++**R)),*L++=(x+y),*R++=(x-y);
		}
	}
	IMP(n,(f[i].x/=n,f[i].y/=n));for(int i=1;(i<<1)<n;++i)swap(f[i],f[n-i]);
}
inline void Solve(const int&L,const int&R){
	if(L==R)return void(ans[0]+=1ll*a[L]*b[R]);
	const int&mid=L+R>>1,&m=R-L+1,&len=Getlen(m<<1);Solve(L,mid);Solve(mid+1,R);
	for(int i=mid+1;i<=R;++i)f[i-L].x=a[i];for(int i=L;i<=mid;++i)f[m-i+L].y=b[i];
	DFT(f,len);IMP(1<<len,f[i]=f[i]*f[i]);IDFT(f,len);
	for(int i=m;i^m<<1;++i)ans[i-m]+=((long long)(f[i].y+.5))/2;IMP(1<<len,f[i]=0);
	for(int i=L;i<=mid;++i)f[i-L].x=a[i];for(int i=mid+1;i<=R;++i)f[i-L].y=b[i];
	DFT(f,len);IMP(1<<len,(f[i]=f[i]*f[i]));IDFT(f,len);
	for(int i=0;i^m<<1;++i)ans[i+L+L]+=((long long)(f[i].y+.5))/2;IMP(1<<len,f[i]=0);
}
inline int read(){
	int n(0);char s;while(!isdigit(s=getchar()));while(n=n*10+(s&15),isdigit(s=getchar()));return n;
}
inline void write(long long n){
	static char s[15];int top(0);while(s[++top]=n%10^48,n/=10);while(putchar(s[top]),--top);putchar(10);
}
signed main(){
	T=read();init(1<<18);
	while(T--){
		n=read();m=read();q=read();while(n--)++a[read()];while(m--)++b[read()];Solve(0,50000);
		while(q--)write(ans[read()]);for(int i=0;i^M;++i)a[i]=b[i]=ans[i]=0;
	}
}
posted @ 2022-06-23 14:46  Prean  阅读(1)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};