[玲珑OJ1044] Quailty and Binary Operation (FFT+cdq分治)
题意:给定两个长度为n的数组a与长度为m的数组b, 给定一个操作符op满足 x op y = x < y ? x+y : x-y. 有q个询问,每次给出询问c,问:有多少对(i, j)满足a[i] op b[j] = c ?
0 <= c <= 100000, 其余数据范围在[0, 50000].
题解:问题的关键在于如何分隔开 x < y与x >= y. cdq分治,合并的时候a[l, mid]与b[mid+1, r]卷积一次计算a[] < b[] , a[mid+1, r]与b[l, mid]再卷积一次a[] > b[]即可。
卡时,memset的时候优化了一下。
1 #include <bits/stdc++.h> 2 typedef long long ll; 3 using namespace std; 4 const int N = 1e5+5; 5 struct comp{ 6 double r,i;comp(double _r=0,double _i=0){r=_r;i=_i;} 7 comp operator+(const comp x){return comp(r+x.r,i+x.i);} 8 comp operator-(const comp x){return comp(r-x.r,i-x.i);} 9 comp operator*(const comp x){return comp(r*x.r-i*x.i,r*x.i+i*x.r);} 10 }x[N<<1], y[N<<1]; 11 const double pi=acos(-1.0); 12 void FFT(comp a[],int n,int t){ 13 for(int i=1,j=0;i<n-1;i++){ 14 for(int s=n;j^=s>>=1,~j&s;); 15 if(i<j)swap(a[i],a[j]); 16 } 17 for(int d=0;(1<<d)<n;d++){ 18 int m=1<<d,m2=m<<1; 19 double o=pi/m*t;comp _w(cos(o),sin(o)); 20 for(int i=0;i<n;i+=m2){ 21 comp w(1,0); 22 for(int j=0;j<m;j++){ 23 comp &A=a[i+j+m],&B=a[i+j],t=w*A; 24 A=B-t;B=B+t;w=w*_w; 25 } 26 } 27 } 28 if(t==-1)for(int i=0;i<n;i++)a[i].r/=n; 29 } 30 int a[N], b[N], n, m, q; 31 ll ans[N]; 32 void cdq(int l, int r){ 33 if(l == r){ 34 ans[0] += a[l]*b[l]; 35 return; 36 } 37 int mid = l+r >> 1; 38 cdq(l, mid); 39 int len = 1; 40 while(len <= (r-l+1)) len <<= 1; 41 memset(x, 0, sizeof(comp)*len ); 42 memset(y, 0, sizeof(comp)*len ); 43 for(int i = l; i <= mid; i++) 44 x[i-l] = comp(a[i], 0); 45 for(int i = mid+1; i <= r; i++) 46 y[i-mid-1] = comp(b[i], 0); 47 FFT(x, len, 1); FFT(y, len, 1); 48 for(int i = 0; i < len; i++) 49 x[i] = x[i]*y[i]; 50 FFT(x, len, -1); 51 for(int i = l+mid+1; i <= mid+r; i++) 52 ans[i] += x[i-l-mid-1].r+0.5; 53 for(int i = 0; i < len; i++) 54 x[i] = y[i] = comp(0, 0); 55 for(int i = mid+1; i <= r; i++) 56 x[i-mid-1] = comp(a[i], 0); 57 for(int i = l; i <= mid; i++) 58 y[mid+1-i] = comp(b[i], 0); 59 FFT(x, len, 1); FFT(y, len, 1); 60 for(int i = 0; i < len; i++) 61 x[i] = x[i]*y[i]; 62 FFT(x, len, -1); 63 for(int i = 1; i <= r-l; i++) 64 ans[i] += x[i].r+0.5; 65 cdq(mid+1, r); 66 } 67 68 int main(){ 69 int t, x, maxn; scanf("%d", &t); 70 while(t--){ 71 scanf("%d%d%d", &n, &m, &q); 72 maxn = 0; 73 for(int i = 0; i < n; i++){ 74 scanf("%d", &x); 75 maxn = max(maxn, x); 76 a[x]++; 77 } 78 for(int i = 0; i < m; i++){ 79 scanf("%d", &x); 80 maxn = max(maxn, x); 81 b[x]++; 82 } 83 cdq(0, maxn); 84 while(q--){ 85 scanf("%d", &x); 86 printf("%lld\n", ans[x]); 87 } 88 memset(a, 0, sizeof(int)*(maxn+3)); 89 memset(b, 0, sizeof(int)*(maxn+3)); 90 memset(ans, 0, sizeof(ll)*(maxn*2+3)); 91 } 92 return 0; 93 }
诸神对凡人心生艳羡,厌倦天堂。