BZOJ4868:[SHOI2017]期末考試——題解
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]期末考試——題解