LOJ #2141. 「SHOI2017」期末考试

题目链接

LOJ #2141

题解

据说这道题可以三分(甚至二分)?
反正我是枚举的 = =

先将t和b数组排序后计算出前缀和,
然后枚举最晚的出成绩时间,每次可以O(1)直接计算调整到该时间所需的代价。

如何计算?
对于学生不满意造成的代价,是 (不满意人数 * 最晚结束时间) - 所有不满的人的t之和;
对于调整老师造成的代价, A < B 时先用A调整 (可用前缀和计算出有多少时间能用来交换,又有多少时间需要被交换)再用B调整仍超出的部分; 否则都用B调整。

真的如高大佬所言是sb题啊 = =
为什么当年的我不会啊

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#define space putchar(' ')
#define enter putchar('
')
using namespace std;
typedef unsigned long long ll;
template <class T>
void read(T &x){
    char c;
    bool op = 0;
    while(c = getchar(), c < '0' || c > '9')
	if(c == '-') op = 1;
    x = c - '0';
    while(c = getchar(), c >= '0' && c <= '9')
	x = x * 10 + c - '0';
    if(op) x = -x;
}
template <class T>
void write(T x){
    if(x < 0) putchar('-'), x = -x;
    if(x >= 10) write(x / 10);
    putchar('0' + x % 10);
}

const int N = 100005;
ll n, m, A, B, C, t[N], sumt[N], b[N], sumb[N], tim, ans = 1LL << 62;

int main(){

    read(A), read(B), read(C);
    read(n), read(m);
    for(ll i = 1; i <= n; i++) read(t[i]);
    sort(t + 1, t + n + 1);
    for(ll i = 1; i <= n; i++) sumt[i] = sumt[i - 1] + t[i];
    for(ll i = 1; i <= m; i++) read(b[i]);
    sort(b + 1, b + m + 1);
    for(ll i = 1; i <= m; i++) sumb[i] = sumb[i - 1] + b[i];
    ll pt = 0, pb = 0;
    for(tim = 0; tim <= b[m]; tim++){
	while(pt < n && t[pt + 1] < tim) pt++;
	while(pb < m && b[pb + 1] < tim) pb++;
	ll sumbl = pb * tim - sumb[pb], sumbr = sumb[m] - sumb[pb] - (m - pb) * tim;
	ll res = min(sumbr * B, min(sumbl, sumbr) * A + (sumbr - min(sumbl, sumbr)) * B);
	res += (pt * tim - sumt[pt]) * C;
	ans = min(ans, res);
    }
    write(ans), enter;

    return 0;
}

原文地址:https://www.cnblogs.com/RabbitHu/p/LOJ2141.html