【p3745】[六省联考2017]期末考试

来源:互联网 发布:手机淘宝怎么实名 编辑:程序博客网 时间:2024/06/04 17:40

传送门~~(诶嘿嘿)

题目大意

有n位同学,每位同学都参加了全部的m门课程的期末考试,都在焦急的等待成绩的公布。
第i位同学希望在第ti天或之前得知所有课程的成绩。如果在第ti天,有至少一门课程的成绩没有公布,他就会等待最后公布成绩的课程公布成绩,每等待一天就会产生C不愉快度。对于第i门课程,按照原本的计划,会在第bi天公布成绩。
有如下两种操作可以调整公布成绩的时间:
将负责课程X的部分老师调整到课程Y,调整之后公布课程X成绩的时间推迟一天,公布课程Y成绩的时间提前一天;每次操作产生A不愉快度。
2.增加一部分老师负责学科Z,这将导致学科Z的出成绩时间提前一天;每次操作产生B不愉快度。
上面两种操作中的参数X;Y;Z均可任意指定,每种操作均可以执行多次,每次执行时都可以重新指定参数。
现在希望你通过合理的操作,使得最后总的不愉快度之和最小,输出最小的不愉快度之和即可。

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

输出格式:
输出一行一个整数,表示最小的不愉快度之和。
输入样例#1:
100 100 2
4 5
5 1 2 3
1 1 2 3 3
输出样例#1:
6
输入样例#2:
3 5 4
5 6
1 1 4 7 8
2 3 3 1 8 2
输出样例#2:
33

思路

这题吧,我的神犇同学都说是三分,时间复杂度是n*log3(n)
但是我觉得这题,可以O(Kn)解决(k<=5)
首先我们预处理三个数组,分别表示选择在第i天出成绩调老师,加老师,以及学生的不满意度
(注:C=1e16,需特判)
然后O(n)查找出成绩的时间
取最小的输出就好了

代码

#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#define ll long long#define N 100010#define inf 100000000000000000llusing namespace std;ll ti[N],b[N];ll A,B,C;ll qz[N],qb[N];ll cn[N],cb[N];ll n,m;int main(){      scanf("%lld%lld%lld",&A,&B,&C);    scanf("%lld%lld",&n,&m);    ll mx=0,fw=0;    for(int i=1;i<=n;++i) scanf("%lld",&ti[i]),fw=max(fw,ti[i]),cn[ti[i]]++,qz[ti[i]]+=ti[i];    for(int i=1;i<=m;++i) scanf("%lld",&b[i]),cb[b[i]]++,qb[b[i]]+=b[i],mx=max(mx,b[i]);    int pfw=max(fw,mx);    for(int i=1;i<=pfw;++i) cn[i]+=cn[i-1],qz[i]+=qz[i-1];    for(int i=1;i<=pfw;++i) cb[i]+=cb[i-1],qb[i]+=qb[i-1];    if(C==0) {printf("0");return 0;}    ll ans=inf;    for(int h=1;h<=mx;++h){        ll o=cn[h]*h-qz[h],t=o*C;        if(C>inf/1000 && o) continue;        if(B<=A) t+=B*(qb[mx]-qb[h]-(cb[mx]-cb[h])*h);        else{            ll t1=cb[h-1]*h-qb[h-1],t2=qb[mx]-qb[h]-(cb[mx]-cb[h])*h;            if(t1>=t2) t+=A*t2;            else t+=t1*A+B*(t2-t1);        }        if(ans>t) ans=t;    }    printf("%lld",ans);    return 0;}
原创粉丝点击