T1
老王雪
1.1 (n, m ≤ 10)
每次修改完后,枚举所有可能的(n!)种配对方案,计算最大、最小值。
时间复杂度(O(m ∗ n!))。期望得分:10.
1.2 (n, m ≤ 2000)
注意到最小的质量之和一定是将(p)和(v)分别按从小到大和从大到小排序,并将对应数字分别配对。最大的质量之和是将(p)和(v)均按从小到大排序,将对应数字分别配对。每次修改后在有序的数组中二分修改的数字,则只需要将该数字的位置进行调整,就能得到有序的数组。每次修改完后(O(n))统计答案。
时间复杂度(O(nm))。期望得分:55.
1.3
参照1.2的做法,注意到(|delta| = 1),若(delta = 1),则找到修改的数字在有序数组中最后一次出
现的位置,将该位置的数(+1),得到的仍然是一个有序的数组,只要修改这一位对答案的贡献即可。同
理当(delta = −1)时,找到修改的数在有序数组中第一次出现的位置,令该位置上的数(−1)并维护答案。
时间复杂度(O(n log n))。期望得分:100.
总体来说这道题的核心是排序不等式,虽然名字十分的高大上,但实际上就是很好感性的一个结论,两个数组,保证(max[i]*max[j],i,j)依次递减,则这两个数组的积一定为满足(max).
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
#define LL long long
const int N = 300005;
int n, m, a[N], b[N], p[N], q[N];
LL ans1, ans2;
void solve(int * a, int * b, int w, int del)
{
if (del == 1)
{
int p = upper_bound(a + 1, a + n + 1, w) - a - 1;
a[p]++;
ans1 += b[n - p + 1]; ans2 += b[p];
}
else
{
int p = lower_bound(a + 1, a + n + 1, w) - a;
a[p]--;
ans1 -= b[n - p + 1]; ans2 -= b[p];
}
}
int main()
{
freopen("chemist.in", "r", stdin);
freopen("chemist.out", "w", stdout);
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]), p[i] = a[i];
}
for (int i = 1; i <= n; i++) {
scanf("%d", &b[i]), q[i] = b[i];
}
sort(a + 1, a + n + 1);
sort(b + 1, b + n + 1);
for (int i = 1; i <= n; i++) ans1 += (LL)a[i] * b[n - i + 1], ans2 += (LL)a[i] * b[i];
printf("%lld %lld
", ans1, ans2);
while (m--)
{
int ty, x, del;
scanf("%d%d%d", &ty, &x, &del);
if (ty == 1) solve(a, b, p[x], del), p[x] += del;
else solve(b, a, q[x], del), q[x] += del;
printf("%lld %lld
", ans1, ans2);
}
return 0;
}