传送门:点击打开链接
题意:给出A数组和B数组,对于每一个A[i],B[j],如果A[i]>=B[j],则变成A[i]-B[j],否则A[i]+B[j]
思路:很显然可以看出fft。但是刚开始却很难想到怎么去把两种情况给分开。
这里有个非常神奇的思路,那就是分治,把区间分成2个部分。A[l,m],A[m+1,r],B[l,m],B[m+1,r]
计算A[l,m]和B[l,m],以及A[m+1,r]和B[m+1,r]对答案贡献时,直接递归
计算A[l,m]和B[m+1,r],以及A[m+1,r]和B[l,m]对答案的贡献时,用fft
这里fft时也非常有技巧,因为两个数组完全独立,所以最后的总长度到达当前递归时区间长度就行了。
关于fft时下标的前后转换,我们可以通过表示出之前的下标,和变换后的下标直接的等量关系,
可以定向的通过数学表达式而搞定。
这道题比较卡时间,顺手加了个输入挂
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <stack>
#include <queue>
#include <cstdio>
#include <cctype>
#include <bitset>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
#define fuck(x) cout<<"["<<x<<"]";
#define FIN freopen("input.txt","r",stdin);
#define FOUT freopen("output.txt","w+",stdout);
using namespace std;
typedef long long LL;
const double PI = acos(-1.0);
struct complex {
double r, i;
complex(double _r = 0.0, double _i = 0.0) {
r = _r; i = _i;
}
complex operator +(const complex &b) {
return complex(r + b.r, i + b.i);
}
complex operator -(const complex &b) {
return complex(r - b.r, i - b.i);
}
complex operator *(const complex &b) {
return complex(r * b.r - i * b.i, r * b.i + i * b.r);
}
};
void change(complex y[], int len) {
int i, j, k;
for(i = 1, j = len / 2; i < len - 1; i++) {
if(i < j) swap(y[i], y[j]);
k = len / 2;
while(j >= k) {
j -= k;
k /= 2;
}
if(j < k) j += k;
}
}
void fft(complex y[], int len, int on) {
change(y, len);
for(int h = 2; h <= len; h <<= 1) {
complex wn(cos(on * 2 * PI / h), sin(on * 2 * PI / h));
for(int j = 0; j < len; j += h) {
complex w(1, 0);
for(int k = j; k < j + h / 2; k++) {
complex u = y[k];
complex t = w * y[k + h / 2];
y[k] = u + t;
y[k + h / 2] = u - t;
w = w * wn;
}
}
}
if(on == -1) {
for(int i = 0; i < len; i++) {
y[i].r /= len;
}
}
}
const int MX = 2e5 + 5;
complex a[MX], b[MX];
int n, m, q;
int A[MX], B[MX];
LL ans[MX];
void solve1(int L, int R) {
int M = (L + R) >> 1, w = R - L + 1, len;
for(len = 1; len < w; len <<= 1);
for(int i = 0; i < len; i++) {
a[i] = (i + L <= M) ? complex(A[i + L], 0) : complex(0, 0);
b[i] = (M + 1 + i <= R) ? complex(B[M + 1 + i], 0) : complex(0, 0);
}
fft(a, len, 1); fft(b, len, 1);
for(int i = 0; i < len; i++) {
a[i] = a[i] * b[i];
}
fft(a, len, -1);
for(int i = 0; i < len; i++) {
LL t = a[i].r + 0.5;
ans[L + M + 1 + i] += t;
}
}
void solve2(int L, int R) {
int M = (L + R) >> 1, w = R - L + 1, len;
for(len = 1; len < w; len <<= 1);
for(int i = 0; i < len; i++) {
a[i] = (M + 1 + i <= R) ? complex(A[M + 1 + i], 0) : complex(0, 0);
b[i] = (i + L <= M) ? complex(B[M - i], 0) : complex(0, 0);
}
fft(a, len, 1); fft(b, len, 1);
for(int i = 0; i < len; i++) {
a[i] = a[i] * b[i];
}
fft(a, len, -1);
for(int i = 0; i + 1 < len; i++) {
LL t = a[i].r + 0.5;
ans[i + 1] += t;
}
}
void cdq(int L, int R) {
if(L == R) {
ans[0] += (LL)A[L] * B[L];
return;
}
int M = (L + R) >> 1;
cdq(L, M); cdq(M + 1, R);
solve1(L, R); solve2(L, R);
}
namespace IO {
const int MT = 2e7;
char buf[MT]; int c, sz;
void begin() {
c = 0;
sz = fread(buf, 1, MT, stdin);
}
inline bool read(int &t) {
while(c < sz && buf[c] != '-' && (buf[c] < '0' || buf[c] > '9')) c++;
if(c >= sz) return false;
bool flag = 0; if(buf[c] == '-') flag = 1, c++;
for(t = 0; c < sz && '0' <= buf[c] && buf[c] <= '9'; c++) t = t * 10 + buf[c] - '0';
if(flag) t = -t;
return true;
}
}
int main() {
int T; //FIN;FOUT;
IO::begin();
IO::read(T);
while(T--) {
memset(ans, 0, sizeof(ans));
memset(A, 0, sizeof(A));
memset(B, 0, sizeof(B));
int Max = 0;
IO::read(n); IO::read(m); IO::read(q);
for(int i = 1; i <= n; i++) {
int t; IO::read(t);
Max = max(Max, t);
A[t]++;
}
for(int i = 1; i <= m; i++) {
int t; IO::read(t);
Max = max(Max, t);
B[t]++;
}
cdq(0, Max);
while(q--) {
int t; IO::read(t);
printf("%lld\n", ans[t]);
}
}
return 0;
}