$dp[i][j]$表示前$i$个仓库由前$j$个人来守卫能取得的最大安全值;
$cost[i][j]$表示前$i$个仓库由前$j$个人来守护在能取得的最大安全值的情况下的最小花费。
AC代码
//#define LOCAL
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
const int maxn = 100 + 5;
const int maxm = 30 + 5;
int a[maxm];
int dp[maxn][maxm], cost[maxn][maxm];
void solve(int n, int m) {
// init
memset(dp, 0, sizeof(dp));
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
// not choose j
dp[i][j] = dp[i][j-1];
// choose j
for(int k = 1; k <= i; k++) {
int x;
if(k == i) x = a[j] / k;
else x = min(a[j] / k, dp[i-k][j-1]);
if(x > dp[i][j]) {
dp[i][j] = x;
}
}
}
}
memset(cost, INF, sizeof(cost));
memset(cost[0], 0, sizeof(cost[0]));
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
cost[i][j] = cost[i][j-1];
for(int k = 1; k <= i; k++) {
int safe = a[j] / k;
if(safe >= dp[n][m]) {
cost[i][j] = min(cost[i][j], cost[i-k][j-1] + a[j]);
}
}
}
}
}
int main() {
#ifdef LOCAL
freopen("data.in", "r", stdin);
freopen("data.out", "w", stdout);
#endif
int n, m;
while(scanf("%d%d", &n, &m) == 2 && n && m) {
for(int i = 1; i <= m; i++) {
scanf("%d", &a[i]);
}
solve(n, m);
printf("%d %d\n", dp[n][m], dp[n][m]==0?0:cost[n][m]);
}
return 0;
}
如有不当之处欢迎指出!