BZOJ 4836 二元运算
2018-01-30 19:04
155 查看
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
22 1 5
1 3
2
1 2 3 4 5
2 2 5
1 3
2 4
1 2 3 4 5
Sample Output
10
1
0
0
1
0
1
0
1
将数塞如一个桶,a[i]表示a中i这个数有多少个,b同样
如果a[1]=2,b[3]=3,那么ans[4]+=a[1]*b[3]
发现加法通过构造形成了卷积,减法通过反转也是卷积
因为分两种情况,不能直接卷积
分治时,考虑[l,mid]的数opt [mid+1,r]的数产生的答案
用两个FFT解决
此题卡常,不要用STL的向量
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<complex> using namespace std; typedef long long lol; const int NN=50005; double pi=acos(-1.0); struct data { double x,y; }; data A[8*NN],B[8*NN]; int R[8*NN],n,n1,n2,m,N; lol ans[8*NN],a[NN],b[NN]; data operator + (const data &a,const data &b){ return (data){a.x+b.x,a.y+b.y}; } data operator - (const data &a,const data &b){ return (data){a.x-b.x,a.y-b.y}; } data operator * (const data &a,const data &b){ return (data){a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x}; } void FFT(data *D,int len,double o) {int i,j,k; for (i=0;i<len;i++) if (i<R[i]) swap(D[i],D[R[i]]); for (i=1;i<len;i<<=1) { data wn=(data){cos(pi/i),sin(o*pi/i)},x,y; for (j=0;j<len;j+=(i<<1)) { data w=(data){1,0}; for (k=0;k<i;k++,w=w*wn) { x=D[j+k];y=w*D[j+k+i]; D[j+k]=x+y; D[j+k+i]=x-y; } } } } void solve(int l,int r) {int len,lg=0,i; if (l==r) return; int mid=(l+r)/2; len=1; while (len<=r-l+1) len*=2,lg++; for (i=0;i<len;i++) R[i]=(R[i>>1]>>1)|((i&1)<<(lg-1)); for (i=0;i<len;i++) A[i]=B[i]=(data){0,0}; for (i=l;i<=mid;i++) A[i-l]=(data){a[i],0}; for (i=mid+1;i<=r;i++) B[i-mid-1]=(data){b[i],0}; FFT(A,len,1);FFT(B,len,1); for (i=0;i<len;i++) A[i]=A[i]*B[i]; FFT(A,len,-1); for (i=0;i<len;i++) ans[i+l+mid+1]+=(lol)(A[i].x/len+0.5); for (i=0;i<len;i++) A[i]=B[i]=(data){0,0}; for (i=l;i<=mid;i++) A[mid-i]=(data){b[i],0}; for (i=mid+1;i<=r;i++) B[i-mid-1]=(data){a[i],0}; FFT(A,len,1);FFT(B,len,1); for (i=0;i<len;i++) A[i]=A[i]*B[i]; FFT(A,len,-1); for (i=0;i<len;i++) ans[i+1]+=(lol)(A[i].x/len+0.5); solve(l,mid);solve(mid+1,r); } void work() {int i,j,x,q; memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); scanf("%d%d%d",&n,&m,&q); for (i=1;i<=n;i++) { scanf("%d",&x); a[x]++; n1=max(n1,x); } for (i=1;i<=m;i++) { scanf("%d",&x); b[x]++; n2=max(n2,x); } memset(ans,0,sizeof(ans)); N=max(n1,n2); for (i=1;i<=N;i++) ans[0]+=a[i]*b[i]; solve(0,N); for (i=1;i<=q;i++) { scanf("%d",&x); printf("%lld\n",ans[x]); } } int main() {int T; cin>>T; while (T--) work(); }
相关文章推荐
- bzoj 4836: 二元运算
- BZOJ4836 二元运算(分治FFT)
- 4836: [Lydsy2017年4月月赛]二元运算
- bzoj 4836: [Lydsy2017年4月月赛]二元运算 -- 分治+FFT
- bzoj 3209: 花神的数论题 (数位DP)
- bzoj3524/2223 [Poi2014]Couriers
- 【BZOJ 1095】 1095: [ZJOI2007]Hide 捉迷藏 (括号序列+线段树)
- Bzoj 2818: Gcd(莫比乌斯反演)
- 【bzoj1798】[Ahoi2009]Seq 维护序列seq
- 【tarjan+拓扑】BZOJ3887-[Usaco2015 Jan]Grass Cownoisseur
- bzoj 2286: [Sdoi2011]消耗战
- bzoj 3306: 树
- BZOJ 3224 普通平衡树(树状数组)
- Bzoj 1036 树的统计 分类: ACM TYPE 2014-12-29 18:55 72人阅读 评论(0) 收藏
- 【bzoj3036】绿豆蛙的归宿
- bzoj2565: 最长双回文串
- [学习笔记]等价类计数&Polya定理 bzoj1004 [HNOI2008]Cards
- BZOJ_2438_[中山市选2011]杀人游戏 _强连通分量
- BZOJ 3150 [Ctsc2013]猴子 ——期望DP 高斯消元
- [BZOJ 1067][SCOI2007]降雨量