[BZOJ]4868: [Shoi2017]期末考试 三分

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/baidu_36797646/article/details/86011780

Description

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

Solution

稍微思考一下,就会发现这是一个关于最晚出成绩天数的单峰函数,直接三分就可以了。
要注意 C C 非常大时的特判。

Code

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=100010;
const int inf=2147483647;
LL read()
{
    LL x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    return x*f;
}
LL A,B,C;
int n,m;
LL t[Maxn],b[Maxn];
LL calc(LL d)
{
    LL re=0;
    for(int i=1;i<=n;i++)
    if(d<=t[i])break;
    else re+=C*(d-t[i]);
    if(B<=A)
    {
        for(int i=m;i;i--)
        if(b[i]<=d)break;
        else re+=B*(b[i]-d);
    }
    else
    {
        LL t1=0,t2=0;
        for(int i=1;i<=m;i++)
        if(d<=b[i])break;
        else t1+=(d-b[i]);
        for(int i=m;i;i--)
        if(d>=b[i])break;
        else t2+=(b[i]-d);
        if(t2<=t1)re+=A*t2;
        else re+=A*t1+B*(t2-t1);
    }
    return re;
}
int main()
{
    A=read(),B=read(),C=read(),n=read(),m=read();
    for(int i=1;i<=n;i++)t[i]=read();sort(t+1,t+1+n);
    for(int i=1;i<=m;i++)b[i]=read();sort(b+1,b+1+m);
    if(C==10000000000000000LL)return printf("%lld",calc(t[1])),0;
    int l=t[1],r=b[m];
    while(r-l>2)
    {
        int p=(r-l+1)/3,lm=l+p,rm=l+(p<<1);
        if(calc(lm)>calc(rm))l=lm;
        else r=rm;
    }
    printf("%lld",min(calc(l+2),min(calc(l),calc(l+1))));
}

猜你喜欢

转载自blog.csdn.net/baidu_36797646/article/details/86011780