貪欲 & DP
DPか貪欲だろうとは雰囲気で察することができた。
が、具体的な解法が思いつかない。試しに問題からでなく上限から解法を考えてみる。
入力の上限から、( 時間 * 問題数 ) くらいの計算はできそうなので、それを足がかりに DP を考える。
DP[どの問題まで][経過時間] ならできそう。
こうなると、解く順番が問題。
解く問題が決まるということは、ポイントの総和が決まるということ。
なら、解く順番は減少が少なくなるように決めるはず。
( 減少 / 消費時間 ) でソートして試す。サンプル合う。通る。
struct S { lli mx; lli minus; lli req; S (int m, int mi, int r) : mx(m), minus(mi), req(r) {} }; bool f(S a, S b) { return ((double)a.minus / a.req) > ((double)b.minus / b.req); } class TheProgrammingContestDivOne { public: int find(int T, vector <int> mx, vector <int> minus, vector <int> req) { const int N = mx.size(); vector<S> v; for (int i = 0; i < N; ++i) { v.push_back(S(mx[i], minus[i], req[i])); } sort(v.begin(), v.end(), f); const int M = 50 + 5; const int L = 100000 + 5; static lli dp[M][L]; fill(&dp[0][0], &dp[M - 1][L - 1] + 1, 0); for (lli i = 0; i < N; ++i) { for (lli j = 0; j <= T; ++j) { int ni = i + 1; int nj = j + v[i].req; lli point = v[i].mx - (v[i].req + j) * v[i].minus; if (0 <= point && nj <= T) { dp[ni][nj] = max(dp[ni][nj], dp[i][j] + point); } dp[ni][j] = max(dp[ni][j], dp[i][j]); } } return *max_element(&dp[0][0], &dp[M - 1][L - 1] + 1); } };