[luogu] P3745 [六省聯考2017]期末考試 (貪心)
P3745 [六省聯考2017]期末考試
題目描述
有 \(n\) 位同學,每位同學都參加了全部的 \(m\) 門課程的期末考試,都在焦急的等待成績的公布。
第 \(i\) 位同學希望在第 \(t_i\)? 天或之前得知所有課程的成績。如果在第 \(t_i\) 天,有至少一門課程的成績沒有公布,他就會等待最後公布成績的課程公布成績,每等待一天就會產生 \(C\) 不愉快度。
對於第 \(i\) 門課程,按照原本的計劃,會在第 \(b_i\)? 天公布成績。
有如下兩種操作可以調整公布成績的時間:
- 將負責課程 \(X\) 的部分老師調整到課程 \(Y\),調整之後公布課程 \(X\) 成績的時間推遲一天,公布課程 \(Y\)
- 增加一部分老師負責學科 \(Z\),這將導致學科 \(Z\) 的出成績時間提前一天;每次操作產生 \(B\) 不愉快度。
上面兩種操作中的參數 \(X, Y, Z\) 均可任意指定,每種操作均可以執行多次,每次執行時都可以重新指定參數。
現在希望你通過合理的操作,使得最後總的不愉快度之和最小,輸出最小的不愉快度之和即可。
輸入輸出格式
輸入格式:
第一行三個非負整數 \(A, B, C\),描述三種不愉快度,詳見【題目描述】;
第二行兩個正整數 \(n, m\),分別表示學生的數量和課程的數量;
第三行 \(n\) 個正整數 \(t_i\)
第四行 \(m\) 個正整數 \(b_i\),表示按照原本的計劃,每門課程公布成績的時間。
輸出格式:
輸出一行一個整數,表示最小的不愉快度之和。
輸入輸出樣例
輸入樣例#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
說明
【樣例 1 說明】
由於調整操作產生的不愉快度太大,所以在本例中最好的方案是不進行調整; 全部
5 的門課程中,最慢的在第 3 天出成績;
同學 1 希望在第 5 天或之前出成績,所以不會產生不愉快度;
同學 2 希望在第 1 天或之前出成績,產生的不愉快度為 (3 ? 1) ? 2 = 4;
同學 3 希望在第 2 天或之前出成績,產生的不愉快度為 (3 ? 2) ? 2 = 2;
同學 4 希望在第 3 天或之前出成績,所以不會產生不愉快度;
不愉快度之和為 4 + 2 = 6 。
題解
整個題目的貪心在於如何處理\(A<B\),因為,\(A\)的使用會伴隨著一門科目的推遲,也就是說\(A\)的使用次數是有限的。
註意到整個題目的意思就是要我們提前天數,那麽我們可以考慮枚舉天數,網上使用三分和二分的大佬們實在是太巨辣,我只會\(O(n)\)。
那麽當\(A<B\)的時候,我們就根據天數的推移用前綴和統計一下能有幾天可以推遲,然後計算\(A\)使用的次數,不夠的再用\(B\)提前。
整個難點就在於學生和科目隨時間的線性變化,要自己理一理。
我們用一個桶記錄學生忍耐的時間,另一個記錄科目出成績的時間。
那麽隨時間線性變化便是,
每往後一天,記錄這天前有多少科目是可以推遲的,對於推遲的貢獻,
有多少學生是開始忍耐不了的。
有多少科目是還需要提前的,對於提前一共要多少天。
自己好好想一下。不懂可以看代碼。
Code
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#define ll unsigned long long
using namespace std;
const ll MAXN=1e6+5;
ll a,b,c,n,m,N,M,sum,ans=1e18,tot;
ll ti[MAXN],bi[MAXN],bac1[MAXN],bac2[MAXN];
ll s,ss,tt,t1,t2,t3;
ll read(){
ll x=0,w=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*w;
}
int main(){
a=read();b=read();c=read();
n=read();t2=m=read();
for(ll i=1;i<=n;i++)ti[i]=read(),bac1[ti[i]]++;
for(ll i=1;i<=m;i++)bi[i]=read(),bac2[bi[i]]++,ss+=bi[i];
for(ll i=1;i<=100000;i++){
//tt當前不能忍受的人的天數,ss當前需要提前的天數,s是當前可以做貢獻的天數
tt+=bac1[i-1]+t1;t1+=bac1[i-1];
t2-=bac2[i];ss-=bac2[i]+t2;
s+=bac2[i-1]+t3;t3+=bac2[i-1];
sum=tt*c;tot=0;
if(a<b){
tot=min(ss,s);sum+=min(ss,s)*a;
}
sum=sum+max((ss-tot),(ll)0)*b;
ans=min(ans,sum);
}
cout<<ans<<endl;
return 0;
}
[luogu] P3745 [六省聯考2017]期末考試 (貪心)