二分枚举L,可以得出最大的L,然后把所用的钱数当做背包做dp,或者把n个仓库当做背包。
#include"bits/stdc++.h"
using namespace std;
const int INF = 1<<30;
const int MX = 1005;
const int maxn = 3e4;
int V[41];
int n,m;
int a[41],b[41],c[41],dp[maxn+7];
bool judge(int x)
{
int st = 1;
memset(V,0,sizeof(V));
for(int i = 1; i <= n; i++){
while(V[st]+x > a[st]){
st++;
}
V[st] += x;
}
if(st > m) return 0;
return 1;
}
int binary()
{
int l = 1, r = MX;
while(l <= r){
int mid = l+r>>1;
if(judge(mid))
l = mid + 1;
else r = mid - 1;
}
return r;
}
void work(int L)
{
memset(dp,-1,sizeof(dp));
dp[0] = 0;
for(int i = 1; i <= m; i++){
for(int j = maxn; j >= a[i]; j--){
if(dp[j-a[i]]>=0){
dp[j] = max(dp[j],dp[j-a[i]]+a[i]/L);
}
}
}
int ans;
for(int i = 0; i <= maxn; i++){
if(dp[i] >= n){
ans = i;
break;
}
}
printf("%d %d\n",L,ans);
}
int main()
{
while(~scanf("%d%d",&n,&m)){
if(n == 0 && m == 0) break;
for(int i = 1; i <= m; i++){
scanf("%d",&a[i]);
}
a[m+1] = INF;
int L = binary();
if(L == 0){
puts("0 0");
continue;
}
work(L);
}
return 0;
}
#include"bits/stdc++.h"
using namespace std;
const int INF = 1<<30;
const int MX = 1005;
int V[41];
int n,m;
int a[41],dp[202];
bool judge(int x)
{
int st = 1;
memset(V,0,sizeof(V));
for(int i = 1; i <= n; i++){
while(V[st]+x > a[st]){
st++;
}
V[st] += x;
}
if(st > m) return 0;
return 1;
}
int binary()
{
int l = 1, r = MX;
while(l <= r){
int mid = l+r>>1;
if(judge(mid))
l = mid + 1;
else r = mid - 1;
}
return r;
}
void work(int L)
{
memset(dp,0x3f,sizeof(dp));
dp[0] = 0;
for(int i = 1; i <= m; i++){
int v = a[i]/L;
for(int j = 2*n; j >= v; j--){
dp[j] = min(dp[j],dp[j-v]+a[i]);
}
}
int ans;
for(int i = n; i <= 2*n; i++){
if(dp[i] != INF){
ans = dp[i];
break;
}
}
printf("%d %d\n",L,ans);
}
int main()
{
while(~scanf("%d%d",&n,&m)){
if(n == 0 && m == 0) break;
for(int i = 1; i <= m; i++){
scanf("%d",&a[i]);
}
a[m+1] = INF;
int L = binary();
if(L == 0){
puts("0 0");
continue;
}
work(L);
}
return 0;
}