ログインしてください。
公式
D - 作業グループの効率化 / Optimizing Work Groups 解説
by
D - 作業グループの効率化 / Optimizing Work Groups 解説
by
kyopro_friends
この問題は DP で答えを求めることができます。
\(\mathrm{dp}[n]\) を、社員 \(1,2,\ldots,n\) をグループに分けるときの生産性の最大値とします。求める答えは \(\mathrm{dp}[N]\) です。
社員 \(n\) と同じグループになるのが何番の人までかを考えることで、
\(\mathrm{dp}[n]=\max_{0\leq k < n}(\mathrm{dp}[k]+(n-k)\times\sum_{i=k+1}^n P_i)\)
となります。
予め \(P\) の累積和を求めておくことで、 \(\sum_{i=l}^{r}P_i\) は任意の \((l,r)\) に対して \(O(1)\) で得られるとしてよく、このDPは状態数 \(O(N)\) 遷移 \(O(N)\) であるため \(O(N^2)\) で \(\mathrm{dp}[N]\) を求めることができます。
実装例 (C++)
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin >> n;
vector<int> p(n);
for(int i=0; i<n; i++) cin >> p[i];
vector<long long> sump(n+1);
for(int i=0; i<n; i++){
sump[i+1] = sump[i] + p[i];
}
vector<long long> dp(n+1, -1e18);
dp[0] = 0;
for(int i=1; i<=n; i++){
for(int j=0; j<i; j++){
dp[i] = max(dp[i], dp[j] + (sump[i] - sump[j]) * (i - j));
}
}
cout << dp.back() << endl;
}
実装例 (Python)
N = int(input())
P = list(map(int, input().split()))
sumP = [0]
for p in P:
sumP.append(sumP[-1] + p)
dp = [-10**18] * (N+1)
dp[0] = 0
for i in range(1, N+1):
dp[i] = max(dp[j] + (sumP[i] - sumP[j]) * (i - j) for j in range(i))
print(dp[-1])
投稿日時:
最終更新:
