1. 程式人生 > >洛谷 P1412 經營與開發

洛谷 P1412 經營與開發

ace 駕駛 def tex color 左右 xpl size 單詞

P1412 經營與開發

題目描述

4X概念體系,是指在PC戰略遊戲中一種相當普及和成熟的系統概念,得名自4個同樣以“EX”為開頭的英語單詞。

eXplore(探索)

eXpand(拓張與發展)

eXploit(經營與開發)

eXterminate(征服)

——維基百科

今次我們著重考慮exploit部分,並將其模型簡化:

你駕駛著一臺帶有鉆頭(初始能力值w)的飛船,按既定路線依次飛過n個星球。

星球籠統的分為2類:資源型和維修型。(p為鉆頭當前能力值)

1.資源型:含礦物質量a[i],若選擇開采,則得到a[i]*p的金錢,之後鉆頭損耗k%,即p=p*(1-0.01k)

2.維修型:維護費用b[i],若選擇維修,則支付b[i]*p的金錢,之後鉆頭修復c%,即p=p*(1+0.01c)

註:維修後鉆頭的能力值可以超過初始值(你可以認為是翻修+升級)

金錢可以透支。

請作為艦長的你仔細抉擇以最大化收入。

輸入輸出格式

輸入格式:

第一行4個整數n,k,c,w。

以下n行,每行2個整數type,x。

type為1則代表其為資源型星球,x為其礦物質含量a[i];

type為2則代表其為維修型星球,x為其維護費用b[i];

輸出格式:

一個實數(保留2位小數),表示最大的收入。

輸入輸出樣例

輸入樣例#1:
5 50 50 10
1 10
1 20
2 10
2 20
1 30
輸出樣例#1:
375.00

說明

【數據範圍】

對於30%的數據 n<=100

另有20%的數據 n<=1000;k=100

對於100%的數據 n<=100000; 0<=k,c,w,a[i],b[i]<=100;保證答案不超過10^9

“依次飛過n個星球”,第一反應就是動態規劃,然後驗證下無後效性即可。

這題關鍵點為狀態的設計。

<Method 1>

F[i][x]表示到達第i個星球,且鉆頭能力值為x的最大收入值。

x因為是實數,所以要取一定的精度。對於數值範圍都在100的本題,n在10左右的時候毫無壓力。

時空復雜度:O(nx) x為精度範圍。

期望得分:10-30;

<Method 2>

F[i][x][y]表示到達第i個星球,且之前開采過x次,維修過y次。

因為本題開采和維修對鉆頭的影響都是定值。所以鉆頭能力就是w*k^x*c^y

時空復雜度:O(n^3)

期望得分:30

<Method 3>

對於20% k=100的數據,鉆頭開采一次就永久損壞了。所以只需記錄維修過幾次即可。

時空復雜度:O(n^2)

期望得分:20 (配合Method 2為50)

<Method 4>

Method 2一樣的狀態設計。但是x,y的範圍不需要與n相同。因為在隨機情況下,開采和維修的次數寥寥無幾(結合次冪考慮)。

時空復雜度:O(nxy) x,y為選手選擇的範圍

期望得分:30-80

<Method 5>

Method 2一樣的狀態設計,但是使用BFS來進行DP過程,這樣就不會遍歷到沒有被訪問到的狀態,同時選手可以自己加上一些簡單的貪心判斷來減少狀態數量。

時空復雜度:O(?)

期望得分:70-100

<Method 6>

與前5種做法截然不同。前5種做法的最大瓶頸就是“當前鉆頭能力”,下面我們嘗試不存儲“當前鉆頭能力”。

F[i]表示前i個星球的最優收入。很明顯這是不行的,因為當前鉆頭能力會切實影響到後面的過程,不嚴謹的說,當前鉆頭能力有“後效性”。

但是這個當前鉆頭能力對後程的影響無非就是乘上一個數值。(就好像初始鉆頭能力為w,實際上你可以按1來做,最後再把ans乘上w)。

正難則反,F[i]表示第i--n個星球的最優收入,且假設從第i個星球開始時鉆頭能力為1。換句話說,這樣的狀態設計,規定了一個參考系

轉移過程就變得簡單:如果在第i個星球開采,那麽第i+1--n個星球的初始鉆頭能力就是1*(1-0.01k)。換句話說,就是F[i+1]*(1-0.01k)。

所以F[i]=max{F[i+1],F[i+1]*(1-0.01k)+a[i]}

對於維護型星球,大同小異。就系數和代價的正負而已。

觀察方程,F[i]=max{F[i+1],F[i+1]*(1-0.01k)+a[i]}

實際上就是取下i+1--n的最值而已,所以這題實際上就成了貪心。

#include<cstdio>
#include<iostream>
using namespace std;
#define N 100010
int n,t[N],a[N];
double k,c,w,ans=0;
int main(){
    scanf("%d%lf%lf%lf",&n,&k,&c,&w);
    k=1-0.01*k;c=1+0.01*c;//關鍵處理 
    for(int i=1;i<=n;i++) scanf("%d%d",t+i,a+i);
    for(int i=n;i>=1;i--){
        if(t[i]==1)ans=max(ans,ans*k+a[i]);
        else ans=max(ans,ans*c-a[i]);
    }
    printf("%.2lf",ans*w);
    return 0;
}

洛谷 P1412 經營與開發