给定长度为
n
n
n 的数组
a
a
a 和一个整数
k
k
k ,保证
n
n
n 为偶数。
问将
n
n
n 个数两两配对,得到的值为
⌊
a
i
+
a
j
k
⌋
\lfloor\frac{a_i+a_j}{k}\rfloor
⌊kai+aj⌋
问如何配对使得总和最大,最大值是多少
对于每个数 x x x 来说, ⌊ x k ⌋ \lfloor\frac{x}{k}\rfloor ⌊kx⌋ 是不会变的,所以我们先将这部分加上,然后 x x x 变为 x m o d k x\bmod k xmodk 。这样存下所有 x m o d k x\bmod k xmodk 的值。
我们继续考虑在 [ 0 , k − 1 ] [0,k-1] [0,k−1] 内的数 x x x 和 y y y 如果 x + y ≥ k x+y\geq k x+y≥k ,则会给答案加 1 1 1 ,因为 x + y ≤ 2 k − 2 x+y\leq 2k-2 x+y≤2k−2 。
此时,最小的数必然是考虑和最大的数相加判断是否大于等于 k k k ,如果不可以则说明最小的数无法配对凑出一个 ≥ k \geq k ≥k 的。
这部分用双指针实现即可。
时间复杂度: O ( n ) O(n) O(n)
#include
using namespace std;
typedef long long ll;
const int N = 200010, M = 1000;
int x;
int ok[M];
int temp[N];
void solve() {
int n, k;
cin >> n >> k;
memset(ok, 0, k * sizeof(int));
ll ans = 0;
for (int i = 0; i < n; ++i) {
cin >> x;
ans += x / k;
ok[x % k] += 1;
}
int t = 0;
for (int i = 1; i < k; ++i) {
while (ok[i] > 0) temp[t++] = i, ok[i]--;
}
for (int i = 0, j = t - 1; i < j; ++i) {
if (temp[i] + temp[j] >= k) {
ans += 1;
j -= 1;
}
}
cout << ans << "\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) solve();
return 0;
}