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 }

 

posted @ 2019-06-15 19:59  iamunstoppable  阅读(241)  评论(0编辑  收藏  举报