BZOJ 4836: [Lydsy1704月赛]二元运算
给定的数组不好操作,把他弄成桶,存出现的次数。
然后我们发现如果都是$x+y$或者都是$x-y$就是一个卷积,用FFT就行了。
那考虑分治,对于$[l,mid]$和$[mid+1,r]$两段。
要么左区间选$a$数组,要么右区间选。
然后递归处理即可。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define LL long long 4 inline int read() { 5 char ch = getchar(); int x = 0, f = 1; 6 while(ch < '0' || ch > '9') { 7 if(ch == '-') f = -1; 8 ch = getchar(); 9 } 10 while('0' <= ch && ch <= '9') { 11 x = x * 10 + ch - '0'; 12 ch = getchar(); 13 } 14 return x * f; 15 } 16 int aa[50010], bb[50010]; 17 LL cnt[200010]; 18 struct com{ 19 double r, i; 20 com(){ 21 r = i = 0; 22 } 23 com(double a, double b) { 24 r = a, i = b; 25 } 26 com operator + (const com& x) const { 27 return com(r + x.r, i + x.i); 28 } 29 com operator - (const com& x) const { 30 return com(r - x.r, i - x.i); 31 } 32 com operator * (const com& x) const { 33 return com(r * x.r - i * x.i, r * x.i + i * x.r); 34 } 35 } A[200010], B[200010], w[200010]; 36 const double PI = acos(-1.0); 37 int rev[200010]; 38 inline void FFT(com a[], int n) { 39 for(int i = 0; i < n; ++ i) { 40 if(rev[i] > i) { 41 swap(a[rev[i]], a[i]); 42 } 43 } 44 for(int t = n >> 1, d = 1; d < n; d <<= 1, t >>= 1) { 45 for(int i = 0; i < n; i += (d << 1)) { 46 for(int j = 0; j < d; ++ j) { 47 com tmp = w[t * j] * a[i + j + d]; 48 a[i + j + d] = a[i + j] - tmp; 49 a[i + j] = a[i + j] + tmp; 50 } 51 } 52 } 53 } 54 inline int Do(int n, int m) { 55 int L = 0, N = 1; 56 for(; N <= n + m; N <<= 1, ++ L); 57 for(int i = 0; i < N; ++ i) { 58 rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (L - 1)); 59 w[i] = com(cos(2.0 * i * PI / N), sin(2.0 * i * PI / N)); 60 } 61 FFT(A, N); FFT(B, N); 62 for(int i = 0; i < N; ++ i) { 63 A[i] = A[i] * B[i]; 64 w[i].i = -w[i].i; 65 } 66 FFT(A, N); 67 return N; 68 } 69 inline void solve(int l, int r) { 70 if(l == r) { 71 cnt[0] += 1ll * aa[l] * bb[l]; 72 return; 73 } 74 int mid = (l + r) / 2; 75 for(int i = l, j = 0; i <= mid; ++ i, ++ j) { 76 A[j] = com(aa[i], 0); 77 } 78 for(int i = mid + 1, j = 0; i <= r; ++ i, ++ j) { 79 B[j] = com(bb[i], 0); 80 } 81 int N = Do(mid - l + 1, r - mid); 82 for(int i = 0; i <= r - l - 1; ++ i) { 83 cnt[l + mid + 1 + i] += (LL)(A[i].r / N + 0.5); 84 } 85 for(int i = 0; i < N; ++ i) { 86 A[i] = com(0, 0); 87 B[i] = com(0, 0); 88 } 89 for(int i = mid + 1, j = 0; i <= r; ++ i, ++ j) { 90 A[j] = com(aa[i], 0); 91 } 92 for(int i = mid, j = 0; i >= l; -- i, ++ j) { 93 B[j] = com(bb[i], 0); 94 } 95 N = Do(r - mid, mid - l + 1); 96 for(int i = 0; i <= r - l - 1; ++ i) { 97 cnt[i + 1] += (LL)(A[i].r / N + 0.5); 98 } 99 for(int i = 0; i < N; ++ i) { 100 A[i] = com(0, 0); 101 B[i] = com(0, 0); 102 } 103 solve(l, mid); solve(mid + 1, r); 104 } 105 inline void solve() { 106 int n = read(), m = read(), q = read(); 107 memset(aa, 0, sizeof(aa)); 108 memset(bb, 0, sizeof(bb)); 109 memset(cnt, 0, sizeof(cnt)); 110 for(int i = 1; i <= n; ++ i) { 111 ++ aa[read()]; 112 } 113 for(int i = 1; i <= m; ++ i) { 114 ++ bb[read()]; 115 } 116 solve(0, 50000); 117 while(q --) { 118 int x = read(); 119 printf("%lld\n", cnt[x]); 120 } 121 } 122 int main() { 123 int T = read(); 124 while(T --) { 125 solve(); 126 } 127 }