式がいかめしくて戸惑うけど、DP 自体は比較的単純
問題概要
個の値 が与えられる。
これらの中から順序を保っていくつか選ぶ。選び方のスコアは、 個の整数 を選んだとしたとき、
で与えられる。このスコアの最大値を求めよ。
制約
考えたこと
とにかく式がいかめしい。しかしサンプルを見ると分かってくる。たとえば だった場合には、計算式は
となる。 を固定した場合には、
の部分のみ最大化すればよいのだ (それ以外は定数)。よって、次のような DP を組んだ (ここから 0-indexed にする)。
dp[i][j]
← の中から 個選んで、それらに前から をかけて、総和をとった値の最大値
DP 更新式は次のように書ける。
chmax(dp[i+1][j], dp[i][j]); chmax(dp[i+1][j+1], dp[i][j] * 0.9 + P[i]);
以上の解法の計算量は となる。
コード
#include <bits/stdc++.h> using namespace std; template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; } int main() { int N; cin >> N; vector<double> P(N), fac(N+1, 0); for (int i = 0; i < N; ++i) { cin >> P[i]; fac[i+1] = fac[i] * 0.9 + 1.0; } vector<vector<double>> dp(N+1, vector<double>(N+1, 0)); for (int i = 0; i < N; ++i) { for (int j = 0; j <= i; ++j) { chmax(dp[i+1][j], dp[i][j]); chmax(dp[i+1][j+1], dp[i][j] * 0.9 + P[i]); } } double res = -(1LL<<60); for (int j = 1; j <= N; ++j) { chmax(res, dp[N][j] / fac[j] - 1200.0 / sqrt(j)); } cout << fixed << setprecision(10) << res << endl; }