NC20439

[SHOI2017]期末考试

https://ac.nowcoder.com/acm/problem/20439

分析

设经过操作后所有成绩全部公布的时间为 ,所获得的不愉快度为
很小,那么大部分同学都能在其能忍受的时间 内知晓成绩,但是由于 很小, 的情况是很多的,为了使所有科目的成绩都在时间 内出来,就需要将大于 减小,那么就会因为多次修改 获得较多的不愉快度,因此 是比较大的;当 很大,虽然不用怎么修改 ,但是 会超出大部分同学的时限 ,因此 也是比较大的。
根据以上分析, 应当是一个下凸的单峰函数,可以用三分法找到极小值点。
接下来分析如何计算 的值。假设强制所有成绩全部公布的时间为 ,将 分为两部分,等待成绩公布获得的不愉快度,以及修改 使得对于任意 所获得的不愉快度。等待成绩公布获得的不愉快度可以直接简单累加,res+=C*(x-t[i])。接下来讨论修改 使得对于任意 所获得的不愉快度。若 显然将成绩公布时间大于 的课程全部使用操作 调整为 更优;若 显然要尽量使用操作 ,当公布时间小于 的课程全部因操作 导致公布时间推迟到 时,将剩下公布时间大于 的课程使用操作 处理。按照以上为规则,即可在 内得到

代码

#include<iostream>
#include<algorithm>
#include<cstdio>
#define ll long long
#define N 100003
using namespace std;
int t[N],b[N];
int n,m;
ll A,B,C;
ll f(int x)//出成绩的时间为x
{
    int i;
    ll res=0;
    for(i=1;i<=n;i++)
    {
        if(x>t[i])//到截止日期还没出成绩
        {
            res+=C*(x-t[i]);
        }
    }
    //计算更改截止日期的代价
    if(A<B)
    {
        ll extra,need;
        extra=need=0;
        for(i=1;i<=m;i++)
        {
            if(b[i]<x) extra+=x-b[i];
            else if(b[i]>x) need+=b[i]-x;
        }
        //多余的天数为extra,可以用来弥补超过x的天数need
        /*
            当公布时间小于x的课程全部因操作1导致公布时间推迟到x时
            将剩下公布时间大于x的课程使用操作2处理
        */
        if(extra>need) res+=A*need;
        else res+=A*extra+(need-extra)*B;
    }
    else//全部使用操作2
    {
        for(i=1;i<=m;i++)
        {
            if(b[i]>x)
            {
                res+=B*(b[i]-x);
            }
        }
    }
    return res;//获得f(x)
}
int main()
{
    cin>>A>>B>>C;
    cin>>n>>m;
    int i;
    for(i=1;i<=n;i++) scanf("%d",t+i);
    for(i=1;i<=m;i++) scanf("%d",b+i);
    int ans;
    /*
        特判
        当C很大,就要让x=min{t[i]}
        不能让任何一个同学等一天
        否则代价巨大
        也不能让x<min{t[i]}
        否则修改b[i]的代价也会变大
    */
    if(C==10000000000000000)
    {
        ans=0x3f3f3f3f;
        for(i=1;i<=n;i++) ans=min(ans,t[i]);
    }
    else//三分
    {
        int l,r;
        l=r=1;
        for(i=1;i<=n;i++) r=max(r,t[i]);
        while(r-l>=10)//预留的区间为10
        {
            int lmid=l+(r-l)/3;
            int rmid=r-(r-l)/3;
            if(f(lmid)>f(rmid))
            {
                ans=l;
                l=lmid+1;
            }
            else r=rmid-1;
        }
        while(l<=r)
        {
            if(f(l)<f(ans)) ans=l;
            l++;
        }
    }
    cout<<f(ans)<<endl;//输出
    return 0;
}
全部评论

相关推荐

点赞 评论 收藏
分享
双非坐过牢:非佬,可以啊10.28笔试,11.06评估11.11,11.12两面,11.19oc➕offer
点赞 评论 收藏
分享
11-07 13:31
怀化学院 Java
勇敢牛牛不怕难:又疯一个
点赞 评论 收藏
分享
3 收藏 评论
分享
牛客网
牛客企业服务