题目
[USACO 20JAN] Farmer John Solves 3SUM G
分析
考虑初始化出所有答案,由于一个面(二维)内答案可能很多,这种情况下可以考虑算二维的单点,然后二维前缀和即可。本题可以计算
i
∈
(
l
,
r
)
i \in (l, r)
i∈(l,r) 满足
a
i
+
a
l
+
a
r
=
0
a_i + a_l + a_r = 0
ai+al+ar=0 的
i
i
i 数量存入 Sum[l][r]
,然后对 Sum
求一遍二维前缀和,可以得到
j
∈
[
1
,
l
]
,
k
∈
[
1
,
r
]
,
i
∈
(
j
,
k
)
,
j
≠
k
j \in [1, l], k \in [1, r], i \in (j, k), j \neq k
j∈[1,l],k∈[1,r],i∈(j,k),j=k 满足
a
i
+
a
j
+
a
k
=
0
a_i + a_j + a_k = 0
ai+aj+ak=0 的数量,询问时直接前缀和容斥一下输出即可。
代码
#include <bits/stdc++.h>
int Read() {
int x = 0; bool f = false; char c = getchar();
while (c < '0' || c > '9')
f |= c == '-', c = getchar();
while (c >= '0' && c <= '9')
x = x * 10 + (c ^ 48), c = getchar();
return f ? -x : x;
}
const int MAXN = 5000;
const int MAXA = 1000000;
int N, Q;
int A[MAXN + 5];
int Cnt[MAXA * 2 + 5];
long long Sum[MAXN + 5][MAXN + 5];
int main() {
N = Read(), Q = Read();
for (int i = 1; i <= N; i++)
A[i] = Read() + MAXA;
for (int i = 1; i <= N; i++) {
for (int j = i + 1; j <= N; j++) {
int fnd = 3 * MAXA - A[i] - A[j];
if (j > i + 1 && fnd >= 0 && fnd <= 2 * MAXA)
Sum[i][j] = Cnt[fnd];
Cnt[A[j]]++;
}
for (int j = i + 1; j <= N; j++)
Cnt[A[j]]--;
}
for (int i = 1; i <= N; i++)
for (int j = 1; j <= N; j++)
Sum[i][j] += Sum[i][j - 1] + Sum[i - 1][j] - Sum[i - 1][j - 1];
while (Q--) {
int lft = Read(), rgt = Read();
printf("%lld\n", Sum[rgt][rgt]- Sum[lft - 1][rgt] - Sum[rgt][lft - 1] + Sum[lft - 1][lft - 1]);
}
return 0;
}