题意:给定n个相同的仓库,有m个人轮流值守,第i个人的应聘者的能力为pi,如果应聘者看守k个仓库,则仓库安全指数为pi/k的整数部分,求使得所有最小安全系数最大且工人pi最小的设计。
思路:二分+01背包。01背包找到x安全系数下是否能守住n个仓库,不断的二分k,找出最小安全系数最大的值,01背包维护最小的工资。
code:
#include <bits/stdc++.h>
using namespace std;typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;const int INF=0x3fffffff;
const int inf=-INF;
const int N=1000000;
const int M=105;
const int mod=1000000007;
const double pi=acos(-1.0);#define cls(x,c) memset(x,c,sizeof(x))
#define cpy(x,a) memcpy(x,a,sizeof(a))
#define ft(i,s,n) for (int i=s;i<=n;i++)
#define frt(i,s,t) for (int i=s;i>=t;i--)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lrt rt<<1
#define rrt rt<<1|1
#define middle int m=(r+l)>>1
#define lowbit(x) (x&-x)
#define pii pair<int,int>
#define mk make_pair
#define IN freopen("in.txt","r",stdin);
#define OUT freopen("out.txt","w",stdout);int n,m,k;
int p[M],dp[M];
int ok(int x)
{cls(dp,63);dp[0]=0;ft(i,1,m) frt(j,n,1) ft(k,1,j){if (p[i]/k<x) break;dp[j]=min(dp[j],dp[j-k]+p[i]);}if (dp[n]>1e9) return 0;k=dp[n];return 1;
}
int main()
{while (~scanf("%d %d",&n,&m),n+m){ft(i,1,m) scanf("%d",&p[i]);p[++m]=0;k=0;int ans=0,l=0,r=1010;while (l<r-1){int mid=l+(r-l)/2;if (ok(mid)) ans=mid,l=mid;else r=mid;}printf("%d %d\n",ans,k);}
}