(ΦωΦ)<これのつづきですよー。目次はここ。
---
この辺からはさらに難しめのをやろう。
あなたの最大HPは $M$ です。あなたのHPは一日の初めに $1$ だけ減ります。
$N$ 人の魔女がこれからやってきます。
$i$ 番目の魔女がやってくるのは $day[i]$ 日めで、その魔女に勝てる確率は $win[i]$ パーセント、勝つと回復できるHPは $gain[i]$ です。
魔女に負けたらあなたはその時点で死亡します。
魔女と戦うかスルーするか選べるとき、あなたの残りの寿命の期待値を求めてください。SRM 533 Div2 Hard
$2 \le M \le 100{,}000$
$1 \le N \le 50$
$0 \le day[i] \le 5{,}000{,}000$
$0 \le win[i] \le 100$
$1 \le gain[i] \le M$
魔女の情報を適切にソートすること。クラスとか構造体とか使うと管理が楽かもしれない。
(ΦωΦ)<メモ化再帰
#include <iostream>
#include <algorithm>
using namespace std;
class MagicalGirl { public: double maxExpectation(int M, vector<int> day, vector<int> win, vector<int> gain); };
struct Witch {
int day; double win; int gain;
bool operator<(const Witch &another) const { return day < another.day; }
};
int n, m;
vector<Witch> v;
vector<vector<double>> dp;
// i番目の魔女と戦うか戦わないか悩んでる状態、前回終了時のHPはhp。
// この時点での寿命の期待値を返す。
double rec(int i, int hp) {
double &res = dp[i][hp];
if(res > 0) { return res; }
double r0 = v[i-1].day + hp;
if(i == n+1) { return res = r0; } // 魔女がいなくなったら今のHPとこれまでの経過日数の和が寿命になる。
int dif = v[i].day - v[i-1].day; // 前回からの日数。
if(hp-dif <= 0) { return res = r0; } // 今の魔女が来るまでにHPが0になる。
double r1 = rec(i+1, hp-dif), // 戦わない。
// 戦う。
// i番目に勝ったときのHPは "戦う前のHP + 戦って得られるHP" だが m は超えない。
// i番目に負けたときはその時点で寿命が尽きる。
r2 = v[i].win * rec(i+1, min(m, hp-dif+v[i].gain)) + (1-v[i].win) * v[i].day;
return res = max(r1, r2);
}
double MagicalGirl::
maxExpectation(int _m, vector<int> day, vector<int> win, vector<int> gain) {
m = _m;
n = day.size();
dp.assign(n+2, vector<double>(m+1));
v.resize(n+1);
v[0] = Witch(); // 番兵
for(int i=0; i<n; i++) {
v[i+1] = Witch({day[i], win[i]/100.0, gain[i]});
}
sort(v.begin(), v.end()); // 魔女が登場する順番でソート
double res = rec(1, m);
return res;
}
(ΦωΦ)<forループ
#include <iostream>
#include <algorithm>
using namespace std;
class MagicalGirl { public: double maxExpectation(int M, vector<int> day, vector<int> win, vector<int> gain); };
struct Witch {
int day; double win; int gain;
bool operator<(const Witch &another) const { return day < another.day; }
};
int n, m;
vector<vector<double>> dp;
double MagicalGirl::
maxExpectation(int m, vector<int> day, vector<int> win, vector<int> gain) {
int n = day.size();
dp.assign(n+1, vector<double>(m+1));
vector<Witch> v(n+1);
v[0] = Witch();
for(int i=0; i<n; i++) {
v[i+1] = Witch({day[i], win[i]/100.0, gain[i]});
}
sort(v.begin(), v.end());
for(int i=n; i>=0; i--) {
for(int j=0; j<=m; j++) {
double &res = dp[i][j];
double r0 = v[i].day + j;
if(i==n) { res = r0; continue; }
int dif = v[i+1].day - v[i].day;
if(j-dif <= 0) { res = r0; continue; }
double r1 = dp[i+1][j-dif],
r2 = v[i+1].win * dp[i+1][min(m, j-dif+v[i+1].gain)] + (1-v[i+1].win) * v[i+1].day;
res = max(r1, r2);
}
}
double res = dp[0][m];
return res;
}
(ΦωΦ)<つづく