1. 程式人生 > >NOIP模擬賽(by hzwer) T1 小奇挖礦

NOIP模擬賽(by hzwer) T1 小奇挖礦

兩位小數 分解 支付 def namespace max sin code open

【題目背景】

  小奇要開采一些礦物,它駕駛著一臺帶有鉆頭(初始能力值 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 小奇挖礦