题目内容
给定长度为
n
n
n 的数组
a
a
a 和长度为
m
m
m 的数组
b
b
b ,以及一个整数
p
p
p 。
求
∑
i
=
0
n
−
1
∑
j
=
0
m
−
1
min
(
a
i
+
b
j
,
p
)
\sum\limits_{i=0}^{n-1}\sum\limits_{j=0}^{m-1} \min(a_i+b_j,p)
i=0∑n−1j=0∑m−1min(ai+bj,p)
数据范围
- 1 ≤ n , m ≤ 2 × 1 0 5 1\leq n,m \leq 2\times 10^5 1≤n,m≤2×105
- 1 ≤ a i , b j ≤ 1 0 8 1\leq a_i,b_j\leq 10^8 1≤ai,bj≤108
- 1 ≤ p ≤ 2 ⋅ 1 0 8 1\leq p\leq 2\cdot 10^8 1≤p≤2⋅108
题解
对 a a a 和 b b b 从小到大排序,然后对 b b b 作前缀和。
考虑从前往后枚举每个 a i a_i ai ,在 b b b 上二分找到最大的 b j b_j bj 满足 a i + b j < p a_i+b_j<p ai+bj<p,那么有 b j b_j bj 及其左边的部分和 a i a_i ai 相加的结果小于 p p p ,右边的部分和 a i a_i ai 相加的结果大于等于 p p p 。
这部分又可以转化为双指针。
时间复杂度: O ( n log n ) O(n\log n) O(nlogn)
代码
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m, p;
cin >> n >> m >> p;
vector<int> a(n), b(m);
for (int i = 0; i < n; ++i) cin >> a[i];
for (int i = 0; i < m; ++i) cin >> b[i];
sort(a.begin(), a.end());
sort(b.begin(), b.end());
vector<long long> preb(m);
for (int i = 0; i < m; ++i) {
preb[i] = b[i];
if (i > 0) preb[i] += preb[i - 1];
}
long long ans = 0;
for (int i = 0, j = m - 1; i < n; ++i) {
while (j >= 0 && a[i] + b[j] >= p) {
j -= 1;
}
// a[i] + b[j + 1] >= p
if (j == -1) {
ans += 1ll * m * p;
} else {
ans += 1ll * (m - 1 - j) * p;
ans += 1ll * a[i] * (j + 1);
ans += preb[j];
}
}
cout << ans << "\n";
return 0;
}