BZOJ4836 二元运算(分治FFT)
2018-08-09 12:52
483 查看
设A(n)为a中n的个数,B(n)为b中n的个数。如果只考虑加法显然是一个卷积,减法翻转一下也显然是一个卷积。
问题在于两者都有。容易想到分开处理。那么可以考虑分治。即对于值域区间[l,r],分别计算A[l,mid]和B[mid+1,r]的贡献及A[mid+1,r]和B[l,mid]的贡献,然后再递归处理[l,mid]和[mid+1,r]。一定程度上类似于cdq分治。
注意结果可能爆int,用NTT的话不太方便。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 270000 const double PI=3.14159265358979324; struct complex { double x,y; complex operator +(const complex&a) const { return (complex){x+a.x,y+a.y}; } complex operator -(const complex&a) const { return (complex){x-a.x,y-a.y}; } complex operator *(const complex&a) const { return (complex){x*a.x-y*a.y,x*a.y+y*a.x}; } }c ,d ; int T,n,m,q,a ,b ,r ; long long f ; void DFT(int n,complex *a,int p) { for (int i=0;i<n;i++) if (i<r[i]) swap(a[i],a[r[i]]); for (int i=2;i<=n;i<<=1) { complex wn=(complex){cos(2*PI/i),p*sin(2*PI/i)}; for (int j=0;j<n;j+=i) { complex w=(complex){1,0}; for (int k=j;k<j+(i>>1);k++,w=w*wn) { complex x=a[k],y=w*a[k+(i>>1)]; a[k]=x+y,a[k+(i>>1)]=x-y; } } } } void mul(int n,complex *a,complex *b) { for (int i=0;i<n;i++) r[i]=(r[i>>1]>>1)|(i&1)*(n>>1); for (int i=0;i<n;i++) a[i].y=a[i].x-b[i].x,a[i].x=a[i].x+b[i].x; DFT(n,a,1); for (int i=0;i<n;i++) a[i]=a[i]*a[i]; DFT(n,a,-1); for (int i=0;i<n;i++) a[i].x=a[i].x/n/4; } void solve(int l,int r) { if (l==r) {f[0]+=1ll*a[l]*b[l];return;} int mid=l+r>>1; solve(l,mid); solve(mid+1,r); int t=1;while (t<r-l+1) t<<=1; for (int i=0;i<t;i++) c[i].x=c[i].y=d[i].x=d[i].y=0; for (int i=l;i<=mid;i++) c[i-l].x=a[i]; for (int i=mid+1;i<=r;i++) d[i-mid-1].x=b[i]; mul(t,c,d); for (int i=l+mid+1;i<=mid+r;i++) f[i]+=(long long)(c[i-l-mid-1].x+0.5); for (int i=0;i<t;i++) c[i].x=c[i].y=d[i].x=d[i].y=0; for (int i=mid+1;i<=r;i++) c[i-mid-1].x=a[i]; for (int i=l;i<=mid;i++) d[mid-i].x=b[i]; mul(t,c,d); for (int i=1;i<=r-l;i++) f[i]+=(long long)(c[i-1].x+0.5); } int main() { #ifndef ONLINE_JUDGE freopen("bzoj4836.in","r",stdin); freopen("bzoj4836.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif T=read(); while (T--) { n=read(),m=read(),q=read(); memset(f,0,sizeof(f)); memset(a,0,sizeof(a));memset(b,0,sizeof(b)); int x=0,y; for (int i=1;i<=n;i++) x=max(y=read(),x),a[y]++; for (int i=1;i<=m;i++) x=max(y=read(),x),b[y]++; solve(0,x); while (q--) printf(LL,f[read()]); } return 0; }
相关文章推荐
- bzoj 4836: [Lydsy2017年4月月赛]二元运算 -- 分治+FFT
- [第二类斯特林数 组合 分治FFT||多项式求逆] BZOJ 4555 [Tjoi2016&Heoi2016]求和
- bzoj3451 Tyvj1953 Normal(期望概率+点分治+FFT)
- [n点无向图个数 分治FFT || 多项式求逆] BZOJ 3456 城市规划
- bzoj 4836: 二元运算
- bzoj 3451: Tyvj1953 Normal 点分治+fft
- BZOJ 4555: [Tjoi2016&Heoi2016]求和 [分治FFT 组合计数 | 多项式求逆]
- 【BZOJ 3451】Tyvj1953 Normal 思维题+期望概率+FFT+点分治
- [BZOJ4555][TJOI2016&HEOI2016]求和(分治FFT)
- BZOJ 4836 二元运算
- 【BZOJ5119】【CTT2017】生成树计数 DP 分治FFT 斯特林数
- bzoj 3451: Tyvj1953 Normal [fft 点分治 期望]
- 【BZOJ1316】树上的询问 点分治+set
- [Bzoj2152]聪聪可可(点分治)
- bzoj 3745: [Coci2015]Norma【分治】
- 【点分治】bzoj2152 聪聪可可
- bzoj-1492 货币兑换Cash (2)——CDQ分治
- 【BZOJ】3527: [Zjoi2014]力 FFT
- 分治技巧在高级数据结构中的应用——线段树分治(二)&&bzoj4137火星商店问题详解
- bzoj 3527: [Zjoi2014]力 快速傅里叶变换 FFT