1. 程式人生 > >Gym 101666L(簡單dp)

Gym 101666L(簡單dp)

傳送門:

題面:

    PDF

題意:

    你最開始有1升的pink飲料,你想要獲得blue飲料,現在有n個人,每個人都希望用O飲料換取W飲料,每次的轉化率為R。現在你可以跟他們依次的交換飲料,而當你最後得到10升以上的blue飲料後,多餘10升的你將拋棄,問你最多能獲得多少blue飲料。

題目分析:

    簡單的線性dp,令dp[i]為當前編號為i的飲料能夠換取的飲料體積,則有轉移方程

    但是這個題目中,因為人數最多為1e5,而每次可能使得體積*2,因此如果像上面一樣遞推,則必定會導致爆double。

    因此我們需要考慮將每次的匯率化為log2的形式,並將轉移方程變為:

轉移,最後變為原值即可。

程式碼:

#include <bits/stdc++.h>
#define maxn 100005
using namespace std;
struct drink{
    string O,W;
    double rate;
}q[maxn];
map<string,int>mp;
const double INF=1e200;
double dp[maxn];
int main()
{
    int n;
    scanf("%d",&n);
    int cnt=1;
    mp["pink"]=1;
    for(int i=1;i<=n;i++){
        cin>>q[i].O>>q[i].W>>q[i].rate;
        if(!mp.count(q[i].O)) mp[q[i].O]=++cnt;
        if(!mp.count(q[i].W)) mp[q[i].W]=++cnt;
        q[i].rate=log2(q[i].rate);
    }
    for(int i=1;i<=cnt;i++) dp[i]=-INF;
    dp[1]=0;
    for(int i=1;i<=n;i++){
        int idW=mp[q[i].W],idO=mp[q[i].O];
        dp[idO]=max(dp[idO],dp[idW]+q[i].rate);
    }
    if(!mp.count("blue")) puts("0.0000000000");
    else{
        double res=dp[mp["blue"]];
        if(res>log2(10)) puts("10.000000000");
        else printf("%.14f\n",min(10.0,pow(2,res)));
    }
    return 0;
}