NC20439 [SHOI2017]期末考试

题目

题目描述

\(n\) 位同学,每位同学都参加了全部的 \(m\) 门课程的期末考试,都在焦急的等待成绩的公布。第 \(i\) 位同学希望在第 \(t_i\) 天或之前得知所有课程的成绩。如果在第ti天,有至少一门课程的成绩没有公布,他就会等待最后公布成绩的课程公布成绩,每等待一天就会产生 \(C\) 不愉快度。对于第 \(i\) 门课程,按照原本的计划,会在第 \(b_i\) 天公布成绩。有如下两种操作可以调整公布成绩的时间:

1.将负责课程 \(X\) 的部分老师调整到课程 \(Y\) ,调整之后公布课程 \(X\) 成绩的时间推迟一天,公布课程 \(Y\) 成绩的时间提前一天;每次操作产生 \(A\) 不愉快度。

2.增加一部分老师负责学科 \(Z\) ,这将导致学科 \(Z\) 的出成绩时间提前一天;每次操作产生 \(B\) 不愉快度。

上面两种操作中的参数 \(X,Y,Z\) 均可任意指定,每种操作均可以执行多次,每次执行时都可以重新指定参数。

现在希望你通过合理的操作,使得最后总的不愉快度之和最小,输出最小的不愉快度之和即可

输入描述

第一行三个非负整数 \(A,B,C\) ,描述三种不愉快度,详见【问题描述】;
第二行两个正整数 \(n,m(1 ≤ n,m ≤ 10^5)\) , 分别表示学生的数量和课程的数量;
第三行 \(n\) 个正整数 \(t_i\) ,表示每个学生希望的公布成绩的时间;
第四行 \(m\) 个正整数 \(b_i\) ,表示按照原本的计划,每门课程公布成绩的时间。
\(1 ≤ N,M,T_i,B_i ≤ 100000,0 ≤ A,B,C ≤ 100000\)

输出描述

输出一行一个整数,表示最小的不愉快度之和。

示例1

输入

100 100 2
4 5
5 1 2 3
1 1 2 3 3

输出

6

说明

由于调整操作产生的不愉快度太大,所以在本例中最好的方案是不进行调整; 全部
5 的门课程中,最慢的在第 3 天出成绩;
同学 1 希望在第 5 天或之前出成绩,所以不会产生不愉快度;
同学 2 希望在第 1 天或之前出成绩,产生的不愉快度为 (3 - 1) * 2 = 4;
同学 3 希望在第 2 天或之前出成绩,产生的不愉快度为 (3 - 2) * 2 = 2;
同学 4 希望在第 3 天或之前出成绩,所以不会产生不愉快度;
不愉快度之和为 4 + 2 = 6 。

备注

数据范围

img

题解

知识点:三分。

三分最晚的公布的时间,因为其符合单调性,晚于或早于这个时间的最晚公布时间造成的不满意度都会变大,B则答案时间在峰谷。

通过计算最晚时间 \(mid\) 的最优不满意度进行检验答案。先遍历数组计算超时总额 \(need\) 和多余总额 \(rest\)\(rest\) 用于操作 \(1\) 。注意到,若 \(A\geq B\) 肯定优先用操作 \(2\) 提前所有超时课的公布时间,花费是 \(B \cdot need\) ;若 \(A<B\) ,优先用操作 \(1\) ,但可能 \(rest\) 不够,需要用操作 \(2\) 补齐剩余的 \(need\) ,够用的花费是 \(A \cdot need\) ,不够用的花费是 \(A \cdot rest + B \cdot (need - rest)\) 。最后累加 \(C\cdot max(mid-T[i])\) ,得到调整后的学生不满意度,返回花费总和进行比较。

时间复杂度 \(O((m+n)\log B_{max})\)

空间复杂度 \(O(m+n)\)

代码

#include <bits/stdc++.h>
#define ll long long

using namespace std;

ll a, b, c;
int n, m;
int T[100007], B[100007];

ll calc(int mid) {
    ll need = 0, rest = 0, ans = 0;
    for (int i = 0;i < m;i++) {
        if (B[i] <= mid) rest += mid - B[i];
        else need += B[i] - mid;
    }
    if (b <= a) ans += need * b;
    else {
        if (need <= rest) ans += need * a;
        else ans += rest * a + (need - rest) * b;
    }
    for (int i = 0;i < n;i++) ans += max(mid - T[i], 0) * c;
    return ans;
}

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> a >> b >> c >> n >> m;
    for (int i = 0;i < n;i++) cin >> T[i];
    for (int i = 0;i < m;i++) cin >> B[i];

    int l = 1, r = *max_element(B, B + m);
    while (l <= r) {
        int mid1 = l + (r - l) / 3;
        int mid2 = r - (r - l) / 3;
        if (calc(mid1) <= calc(mid2)) r = mid2 - 1;
        else l = mid1 + 1;
    }
    cout << calc(l) << '\n';
    return 0;
}
posted @ 2022-06-29 09:58  空白菌  阅读(69)  评论(0编辑  收藏  举报