BZOJ4836 [Lydsy1704月赛]二元运算

<body> <center><h1>4836: [Lydsy1704月赛]二元运算</h1><span class="green">Time Limit: </span>8 Sec&nbsp;&nbsp;<span class="green">Memory Limit: </span>128 MB<br><span class="green">Submit: </span>1070&nbsp;&nbsp;<span class="green">Solved: </span>365<br>[<a href="submitpage.php?id=4836">Submit</a>][<a href="problemstatus.php?id=4836">Status</a>][<a href="bbs.php?id=4836">Discuss</a>]</center><h2>Description</h2><div class="content"><div>定义二元运算 opt 满足</div> <div><img src="https://www.lydsy.com/JudgeOnline/upload/201704/111.JPG" width="306" height="83" alt=""></div> <div></div> <div>现在给定一个长为 n 的数列 a 和一个长为 m 的数列 b ,接下来有 q 次询问。每次询问给定一个数字 c&nbsp;</div> <div>你需要求出有多少对 (i, j) 使得 a_i &nbsp;opt b_j=c 。</div> <div></div> <div></div> <div></div></div><h2>Input</h2><div class="content"><div>第一行是一个整数 T (1≤T≤10) ,表示测试数据的组数。</div> <div>对于每组测试数据:</div> <div>第一行是三个整数 n,m,q (1≤n,m,q≤50000) 。</div> <div>第二行是 n 个整数,表示 a_1,a_2,?,a_n (0≤a_1,a_2,?,a_n≤50000) 。</div> <div>第三行是 m 个整数,表示 b_1,b_2,?,b_m (0≤b_1,b_2,?,b_m≤50000) 。</div> <div>第四行是 q 个整数,第 i 个整数 c_i (0≤c_i≤100000) 表示第 i 次查询的数。</div> <div></div> <div></div></div><h2>Output</h2><div class="content"><p>对于每次查询,输出一行,包含一个整数,表示满足条件的 (i, j) 对的个数。</p> <div></div> <div></div></div><h2>Sample Input</h2> <div class="content"><span class="sampledata">2<br> 2 1 5<br> 1 3<br> 2<br> 1 2 3 4 5<br> 2 2 5<br> 1 3<br> 2 4<br> 1 2 3 4 5</span></div><h2>Sample Output</h2> <div class="content"><span class="sampledata">1<br> 0<br> 1<br> 0<br> 0<br> 1<br> 0<br> 1<br> 0<br> 1</span></div> <h2>Source</h2> <div class="content"><p><a href="problemset.php?search=鸣谢Tangjz提供试题">鸣谢Tangjz提供试题</a></p></div> </body>

题解

括号中的条件显然可以分治解决,使用分治FFT即可。

翻转操作:\(i-j\)为定值,可以把\(j\)存到\(-j\)中,这样又是和为定值了。注意分析提取和放入的\(x\)次幂。

时间复杂度\(O(n\log^2 n)\),在BZOJ上TLE。复数竟然比我的长整形跑得快。

co int N=1<<20;

void num_trans(LL a[],int lim,int inv){
    static int rev[N],siz;
    if(siz!=lim){
        siz=lim;int len=log2(lim);
        for(int i=0;i<lim;++i) rev[i]=rev[i>>1]>>1|(i&1)<<(len-1);
    }
    for(int i=0;i<lim;++i)if(i<rev[i]) swap(a[i],a[rev[i]]);
    for(int step=1;step<lim;step<<=1){
        LL gn=fpow(inv==1?g:g_inv,(mod-1)/(step<<1));
        for(int even=0;even<lim;even+=step<<1){
            int odd=even+step;LL gk=1;
            for(int k=0;k<step;++k,gk=mul(gk,gn)){
                LL t=mul(gk,a[odd+k]);
                a[odd+k]=add(a[even+k],mod-t),a[even+k]=add(a[even+k],t);
            }
        }
    }
    if(inv==-1){
        LL lim_inv=fpow(lim,mod-2);
        for(int i=0;i<lim;++i) a[i]=mul(a[i],lim_inv);
    }
}

int a[N],b[N];
LL ans[N];

void solve(int l,int r){
	if(l==r){
		ans[0]+=(LL)a[l]*b[l];
		return;
	}
	static LL A[N],B[N];
	int mid=(l+r)>>1,lim=1<<int(ceil(log2(r-l)));
	// a[l~mid] + b[mid+1~r]
	for(int i=0;i<lim;++i) A[i]=B[i]=0;
	for(int i=l;i<=mid;++i) A[i-l]=a[i]; // extract x^l
	for(int i=mid+1;i<=r;++i) B[i-mid-1]=b[i]; // extract x^{mid+1}
	num_trans(A,lim,1),num_trans(B,lim,1);
	for(int i=0;i<lim;++i) A[i]=mul(A[i],B[i]);
	num_trans(A,lim,-1);
	for(int i=0;i<r-l;++i) ans[i+l+mid+1]+=A[i];
	// a[mid+1~r] - b[l~mid]
	for(int i=0;i<lim;++i) A[i]=B[i]=0;
	for(int i=mid+1;i<=r;++i) A[i-mid-1]=a[i]; // extract x^{mid+1}
	for(int i=l;i<=mid;++i) B[mid-i]=b[i]; // inject x^mid
	num_trans(A,lim,1),num_trans(B,lim,1);
	for(int i=0;i<lim;++i) A[i]=mul(A[i],B[i]);
	num_trans(A,lim,-1);
	for(int i=0;i<r-l;++i) ans[i+mid+1-mid]+=A[i];
	
	solve(l,mid),solve(mid+1,r);
}
void real_main(){
	int n=read<int>(),m=read<int>(),q=read<int>();
	for(int i=0;i<=50000;++i) a[i]=b[i]=0;
	while(n--) ++a[read<int>()];
	while(m--) ++b[read<int>()];
	for(int i=0;i<=1000000;++i) ans[i]=0;
	solve(0,50000);
	while(q--) printf("%lld\n",ans[read<int>()]);
}
int main(){
	for(int t=read<int>();t--;) real_main();
	return 0;
}

posted on 2019-07-30 08:33  autoint  阅读(144)  评论(0编辑  收藏  举报

导航