NOIP模擬賽(by hzwer) T1 小奇挖礦
【題目背景】
小奇要開采一些礦物,它駕駛著一臺帶有鉆頭(初始能力值 w)的飛船,按既定
路線依次飛過喵星系的 n 個星球。
【問題描述】
星球分為 2 類:資源型和維修型。
1. 資源型:含礦物質量 a[i],若選擇開采,則得到 a[i]*p 的金錢,之後鉆頭
損耗 k%,即 p=p*(1-0.01k)
2. 維修型:維護費用 b[i],若選擇維修,則支付 b[i]*p 的金錢,之後鉆頭修
復 c%,即 p=p*(1+0.01c)(p 為鉆頭當前能力值)
註:維修後鉆頭的能力值可以超過初始值
請你幫它決策最大化這個收入
【輸入格式】
第一行 4 個整數 n,k,c,w。
以下 n 行,每行 2 個整數 type,x。
type 為 1 則代表其為資源型星球,x 為其礦物質含量 a[i];
type 為 2 則代表其為維修型星球,x 為其維護費用 b[i];
【輸出格式】
輸出一行一個實數(保留兩位小數),表示要求的結果。
【樣例輸入】
5 50 50 10
1 10
1 20
2 10
2 20
130
【樣例輸出】
375.00
【數據範圍】
對於 30%的數據 n<=100
對於 50%的數據 n<=1000,k=100
對於 100%的數據 n<=100000,0<=k,c,w,a[i],b[i]<=100
保證答案不超過 10^9
【解析】
這道題從題面就可以看出是一道動態規劃的題,但有一點顯然的是:前面的決策會影響後面的結果。為了消去前面的影響,我們可以從後邊開始動態規劃。
設f[i]表示在第i個星球的最大收入。若當前點為資源型星球,那麽如果開采就可以獲得當前星球的收入,而由於耐久度會減少,前面所得到的收入要整體下降%k所以狀態轉移方程為f[i]=max(f[i-1],a[i]+f[i-1]*(1-0.01*k))。若當前點為維修型星球,那麽同理可得:減少a[i]並讓前面的收入增加%c,狀態轉移方程為f[i]=max(f[i-1],f[i-1]*(1+0.01*c)-a[i])。為了在狀態轉移時更加方便,我們可以將原來耐久度為w的鉆機分解成w個耐久為一的鉆機,最後給答案乘w即可。
綜上所述,狀態轉移方程為:
f[i]=max(f[i-1],a[i]+f[i-1]*(1-k%)) (t[i]=1)
f[i]=max(f[i-1],f[i-1]*(1+c%)-a[i]) (t[i]=2)
【代碼】
1 #include <iostream> 2 #include <cstdio> 3 #include <iomanip> 4 #define N 100002 5 using namespace std; 6 int n,d[N],a[N],i; 7 double f[N],k,c,w; 8 int main()9 { 10 freopen("explo.in","r",stdin); 11 freopen("explo.out","w",stdout); 12 cin>>n>>k>>c>>w; 13 for(i=1;i<=n;i++) cin>>d[i]>>a[i]; 14 for(i=n;i>=1;i--){ 15 if(d[i]==1) f[i]=max(f[i+1],f[i+1]*(1-0.01*k)+a[i]); 16 else f[i]=max(f[i+1],f[i+1]*(1+0.01*c)-a[i]); 17 } 18 f[1]=f[1]*w; 19 cout<<setprecision(2)<<fixed<<f[1]<<endl; 20 fclose(stdin); 21 fclose(stdout); 22 return 0; 23 }
NOIP模擬賽(by hzwer) T1 小奇挖礦