中考将至,写此题,中考 rp++ 。
Address
https://www.lydsy.com/JudgeOnline/problem.php?id=4868
Solution
由于期末考试中考的到来,写了这一题。
先把问题抽象化:
有
n
n
个数,分别为 。
还有
m
m
个数,分别为 。
操作一:对于一对
i≠j
i
≠
j
,将
bi
b
i
加一,
bj
b
j
减一的代价为
A
A
。
操作二:对于一个 ,将一个
bi
b
i
减一的代价为
B
B
。
上面两种操作可以执行多次。
操作执行完之后,对于任何一个 ,如果
max{b}>ti
max
{
b
}
>
t
i
,则产生的代价为
max{b}−ti
max
{
b
}
−
t
i
。
求最小代价和。
把问题拆开,先对于每个
1≤k≤max{b}
1
≤
k
≤
max
{
b
}
,求出使
max{b}
max
{
b
}
下降到
k
k
的最小代价和。
显然,如果 ,那么操作一是没有意义的。最小代价和为
将 b b 排序后可以求出。
否则可能既有操作一又有操作二(当然操作一要多用)。设 ,那么一定有 bi<k<bj b i < k < b j 。
也就是说,操作一的 i i 一定满足 , j j 一定满足 。
满足 bi<k b i < k 的 b b 值最多可以加一 次。
满足 bj>k b j > k 的 b b 值最多可以减一 次。
所以,这样操作一的执行次数为:
操作二的执行次数:
求出将 max{b} max { b } 降到 k k 的最小代价和后,再加上 ,就可以更新答案。
同样将 t t 排序。
特判: 时,只有 max{b}<min{t} max { b } < min { t } 才能保证最优。为了不爆 long long ,只需要将 k k 从 枚举到 min{t} min { t } 而不是 105 10 5 即可。
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Rof(i, a, b) for (i = a; i >= b; i--)
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
typedef long long ll; const int N = 1e5 + 5;
int A, B, n, m, t[N], b[N], cntt[N], cntl[N], cntr[N], w1[N], w2[N], MaxN = 1e5;
ll C, sumt[N], suml[N], sumr[N], f[N], Ans = ((1ll << 62) - 1 << 1) + 1;
int main() {
int i, sp = 1; A = read(); B = read(); cin >> C; n = read(); m = read();
For (i, 1, n) w1[t[i] = read()]++; For (i, 1, m) w2[b[i] = read()]++;
For (i, 1, MaxN) cntt[i] = cntt[i - 1] + w1[i], cntl[i] = cntl[i - 1] + w2[i],
sumt[i] = sumt[i - 1] + 1ll * w1[i] * i,
suml[i] = suml[i - 1] + 1ll * w2[i] * i; Rof (i, MaxN, 1)
cntr[i] = cntr[i + 1] + w2[i], sumr[i] = sumr[i + 1] + 1ll * w2[i] * i;
while (!w2[MaxN]) MaxN--; For (i, 1, MaxN) {
ll le = 1ll * i * cntl[i] - suml[i], ri = sumr[i] - 1ll * i * cntr[i];
if (A >= B) f[i] = 1ll * ri * B; else if (le >= ri) f[i] = 1ll * ri * A;
else f[i] = 1ll * le * A + 1ll * (ri - le) * B;
}
while (!w1[sp]) sp++; For (i, 1, (C == 1e16 ? min(sp, MaxN) : MaxN))
Ans = min(Ans, f[i] + (1ll * i * cntt[i] - sumt[i]) * C);
cout << Ans << endl; return 0;
}