1. 程式人生 > >BZOJ4868:[SHOI2017]期末考試——題解

BZOJ4868:[SHOI2017]期末考試——題解

ref else read ++ 部分 www. nbsp 復制 兩種

http://www.lydsy.com/JudgeOnline/problem.php?id=4868

題目復制於洛谷:https://www.luogu.org/problemnew/show/P3745#sub

有n位同學,每位同學都參加了全部的m門課程的期末考試,都在焦急的等待成績的公布。

第i位同學希望在第ti天或之前得知所有課程的成績。如果在第ti天,有至少一門課程的成績沒有公布,他就會等待最後公布成績的課程公布成績,每等待一天就會產生C不愉快度。對於第i門課程,按照原本的計劃,會在第bi天公布成績。

有如下兩種操作可以調整公布成績的時間:

1.將負責課程X的部分老師調整到課程Y,調整之後公布課程X成績的時間推遲一天,公布課程Y成績的時間提前一天;每次操作產生A不愉快度。

2.增加一部分老師負責學科Z,這將導致學科Z的出成績時間提前一天;每次操作產生B不愉快度。

上面兩種操作中的參數X;Y;Z均可任意指定,每種操作均可以執行多次,每次執行時都可以重新指定參數。

現在希望你通過合理的操作,使得最後總的不愉快度之和最小,輸出最小的不愉快度之和即可。

感覺像三分最終出成績的時間但是不知道怎麽證明於是看了題解。

首先我們考慮如果我們知道最終發成績的時間的話,那麽我們顯然能得到此時的唯一最優解。

無腦做法:

顯然學生代價C我們立刻能求出來,O(n)無腦。

然後我們考慮AB代價,顯然B的操作要比A優秀,所以當B<=A時顯然只需要B操作即可。

而且B操作代價求法很無腦,一個O(m)就能求。

考慮A操作,先預處理排好序然後無腦加減就可以做到一個O(m)。

所以綜上固定時間求代價的復雜度為O(max(n,m)),且nm數量級一致,簡記做O(n)。

再考慮對於學生來說,顯然時間越小代價越小。

對於老師來說,顯然時間越大代價越大。

復合函數顯然滿足單峰性,可以三分,是一個log的。

所以是O(nlogn),1e5絕對能過。

(我的代碼就是這個)

跑得快做法:

見http://www.cnblogs.com/RabbitHu/p/LOJ2141.html提供了一種O(1)求最優解的方法,再套上三分就可以O(logn)了。

但是相比較而言無腦做法十分的妙(因為無腦啊!考試的時候誰還帶腦子……)。

#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1e5+5;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch==-;ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
ll A,B,C;
int n,m,t[N],b[N],nb[N];
inline ll suan(int ed){
    ll ans=0;
    for(int i=1;i<=n;i++){
        if(t[i]<ed)ans+=(ed-t[i])*C;
        else break;
    }
    for(int i=1;i<=m;i++)nb[i]=b[i];
    if(A<B){
        int l=1,r=m;
        while(l<r){
            if(nb[r]>ed){
                int delta=ed-nb[l];
                if(delta<0)break;
                if(nb[r]-delta>ed){
                    nb[r]-=delta;
                    nb[l++]=ed;
                    ans+=A*delta;
                }else{
                    ans+=A*(nb[r]-ed);
                    nb[l]+=nb[r]-ed;
                    nb[r--]=ed;
                }
            }else break;
        }
    }
    for(int i=m;i>=1;i--){
        if(nb[i]>ed)ans+=(nb[i]-ed)*B;
    }
    return ans;
}
ll sanfen(int l,int r){
    while(233){
        if(r-l<3){
            ll ans=suan(r);
            for(int i=l;i<r;i++)ans=min(ans,suan(i));
            return ans;
        }
        int mid1=l+(r-l)/3,mid2=mid1+(r-l)/3;
        if(suan(mid1)>suan(mid2))l=mid1;
        else r=mid2;
    }
}
int main(){
    A=read(),B=read(),C=read();
    n=read(),m=read();
    for(int i=1;i<=n;i++)t[i]=read();
    for(int i=1;i<=m;i++)b[i]=read();
    sort(t+1,t+n+1);sort(b+1,b+m+1);
    printf("%lld\n",sanfen(t[1],max(t[n],b[m])));
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+歡迎訪問我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

BZOJ4868:[SHOI2017]期末考試——題解