题目来源:
此题我做了好久一直没有发现错误在哪,原本以为可能是关于二分的问题,最后通过单步调试才发现问题就出现在写的公式上(气死了,气死了)(单步调试万岁,嘻嘻)
接下来是本题的思路,首先是暴力解法,时间复杂度是\(O(N^2)\),这显然是不行的。那么此题就需要使用二分进行优化。
1. 首先我们可以这样想,在所有套餐可能中有一些可能是重复的,也就是重复的 \(p\) ,另一部分则是 \(a [ i ]\) 与\(b [ i ]\) 的和\(sum\)。
2. 那么我们要考虑区分p和sum的界限是什么,我们要找到区分这两个区间的值,这个值就是我们需要通过二分去寻找的,也就是p-b [ i ],以下用m代替此值。
3. 当 \(m <= 0\) 时,那么很明显所有可能的组合都是要比p大的,\(min(s,p)=p\) ; 所以总的价值就是\(n*p\) ,\({sum = n * p}\);
4.当m > 0时,两个区间分别的sum分别是 sssssssss....... 和 pppppp...... ,对于p的处理不必多说,通过二分找到边界后,右区间的和sumr就是右区间 \(a [ i ]\) 元素的个数 \(* p\) ,\({sumr=(n - u + 1) * p}\);
而左区间我们可以通过前缀和来处理,\({suml=q [ u - 1 ] + (u - 1) * b[ i ] }\);
最后将\(suml\)与\(sumr\)相加便是答案
#include<bits/stdc++.h>
using namespace std;
#define int long long
//记得开long long
const int N = 2e5 + 10;
int a[N], b[N], q[N];
int n, m, p, i;
int sum, ans;
signed main() {
cin >> n >> m >> p;
for (i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
}
sort(a + 1, a + 1 + n);//对数组a排序
for (i = 1; i <= n; i++) {
q[i] = q[i - 1] + a[i];
//前缀和
}
for (i = 1; i <= m; i++) {
scanf("%lld", &b[i]);
int m = p - b[i];
if (m <= 0) {
ans += n * p;
} else {
//使用stl函数偷懒。
int u = upper_bound(a + 1, a + 1 + n, m) - a;
//激情调试 cout << u << endl;
//u就是我们要找的边界
ans += (n - u + 1) * p;//右区间
// cout << ans << " ";
ans += q[u - 1] + (u - 1) * b[i];
//左区间,在这里一开始我的公式写错了,调了好久,企图偷懒的原因......
// cout << ans << " ";
// cout << ans << endl;
}
}
cout << ans << endl;
}
/*
2 2 7
3 5
6 1
14
10
24
5 5 6
1 2 4 6 8
2 5 4 3 1
13 + 12
6 + 24
11 + 18
9 + 18
10 + 12
*/