Randy Company has N (1 ≤ N ≤ 100) storages. Company wants some men to keep them safe. Nowthere are M (1 ≤ M ≤ 30) men asking for the job. Company will choose several from them. RandyCompany employs men following these rules:
-
Each keeper has a number Pi (1 ≤ Pi ≤ 1000) , which stands for their ability.
-
All storages are the same as each other.
-
A storage can only be lookd after by one keeper. But a keeper can look after several storages. If akeeper’s ability number is Pi, and he looks after K storages, each storage that he looks after hasa safe number Uj = Pi ÷ K.(Note: Uj, Pi and K are all integers). The storage which is lookedafter by nobody will get a number 0.
-
If all the storages is at least given to a man, company will get a safe line L = min Uj
-
Every month Randy Company will give each employed keeper a wage according to his abilitynumber. That means, if a keeper’s ability number is Pi, he will get Pi dollars every month. Thetotal money company will pay the keepers every month is Y dollars.
Now Randy Company gives you a list that contains all information about N, M, P, your task is givecompany a best choice of the keepers to make the company pay the least money under the conditionthat the safe line L is the highest.
Input
The input file contains several scenarios. Each of them consists of 2 lines:
The first line consists of two numbers (N and M), the second line consists of M numbers, meaning
Pi (i = 1..M). There is only one space between two border numbers.The input file is ended with N = 0 and M = 0.
Output
For each scenario, print a line containing two numbers L(max) and Y (min). There should be a spacebetween them.
Sample Input
21
7
12
10 9
25
10 8 6 4 154111100
Sample Output
3710 108 1800
题意:
给你n个仓库,m个人,第i个人的能力值为pi,每个人可守卫多个仓库,每个仓库只能被一人守卫,若第i个人守护k个仓库,则那些仓库的安全值为pi/k的整数部分,设所有仓库中安全值最低的为t,要求t最大的情况下,消耗最少的能力值。
分析:
第一次dp,求出n个仓库m个人可获得的最大的t。
f[i][j]表示前i个人守护j个仓库的最低安全值,可得f[i][j]=max(f[i][j],min(pi/k,f[i-1][j-k]))
第二次dp,求出在安全值为t的情况下,消耗最少的能力值。
g[i][j]表示前i个人守护j个仓库在安全值最大情况下花费最少的能力值,可得当pi/k>=f[m][n]时,g[i][j]=min(g[i][j],g[i-1][j-k]+pi)
以上k均表示第i个人守护k个仓库时的情况。
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;
#define INF 0x3f3f3f3f
const int N=105;
const int mod=1e9+7;
int p[N],f[N][N],g[N][N];
int main() {
int n,m;
while (cin>>n>>m&&n) {
for (int i=1; i<=m; i++) {
cin>>p[i];
}
memset(f, 0, sizeof(f));
memset(g, INF, sizeof(g));
for (int i=1; i<=m; i++) {
f[i-1][0]=INF;
for (int j=1; j<=n; j++) {
f[i][j]=f[i-1][j];
for (int k=1; k<=j; k++) {
f[i][j]=max(min(p[i]/k, f[i-1][j-k]),f[i][j]);
}
}
}
if (f[m][n]==0) {
g[m][n]=0;
} else {
for (int i=1; i<=m; i++) {
g[i-1][0]=0;
for (int j=1; j<=n; j++) {
g[i][j]=g[i-1][j];
for (int k=1; k<=j; k++) {
if (p[i]/k>=f[m][n]) {
g[i][j]=min(g[i][j], g[i-1][j-k]+p[i]);
}
}
}
}
}
cout<<f[m][n]<<" "<<g[m][n]<<endl;
}
return 0;
}