【题解】
一开始看着题觉得是二分答案(最大值的最小值),后来发现不满足单调性
再后来发现可以用贪心做:只需把大臣按照左手*右手升序排序即可
证明:
很显然前面的大臣位置随便调换对后面的大臣并没有影响
那么假设现在已经排了i-1个大臣,p=a[1]*a[2]*a[3]*……*a[i-1];
第i个大臣的钱w[i]=p/b[i],第i+1个大臣的钱w[i+1]=p*a[i]/b[i+1]
若i+1大臣在i大臣前面
第i个大臣的钱w[i]=p*a[i+1]/b[i],第i+1个大臣的钱w[i+1]=p/b[i+1]
显然p*a[i+1]/b[i]>p/b[i] && p*a[i]/b[i+1]>p/b[i+1]
所以两个里面的最大值在p*a[i+1]/b[i] 和 p*a[i]/b[i+1] 之间
若p*a[i+1]/b[i] > p*a[i]/b[i+1](这样就是i+1大臣排在i后面最大值会更小) 则 a[i+1]*b[i+1]>a[i]*b[i]
所以如果要让大臣得到的钱的最大值最小就要保证两个相邻的大臣,前面的左手*右手<后面的左手*右手
(一年前打的题目,现在写题解还要写好久,果然我还是太菜了)
详见代码(记得打高精度,还有interesting的高精除法噢233)
#include <algorithm>
#include <iostream>
#include <ctime>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <map>
#include <cstring>
#include <string>
using namespace std;
struct info
{
int l,r,k;
}num[1001];
inline bool cmp(const info &a,const info &b)
{
return a.k<b.k;
}
int f[20000];
int i,j,k,l,m,n,t;
int main()
{
scanf("%d",&n);
for(i=0;i<=n;i++)
{
scanf("%d%d",&num[i].l,&num[i].r);
num[i].k=num[i].r*num[i].l;
}
sort(num+1,num+n+1,cmp);
f[1]=num[0].l;f[0]=1;
for (int i=1;i<=n-1;i++)
{
t=0;
for (int j=1;j<=f[0];j++)
{
f[j]*=num[i].l;f[j]+=t;
t=f[j]/10000;f[j]%=10000;
}
if (t>0) f[++f[0]]=t;
}
t=0;
for (int i=f[0];i>=1;i--)
{
t+=f[i];f[i]=t/num[n].r;
t%=num[n].r;
t*=10000;
}
for (;f[f[0]]==0 && f[0]>0;f[0]--);
if (f[f[0]]==0) printf("1");else printf("%d",f[f[0]]);
for (int i=f[0]-1;i>=1;i--)
{
if (f[i]<10) printf("000");
if (f[i]<100 && f[i]>=10) printf("00");
if (f[i]<1000 && f[i]>=100) printf("0");
printf("%d",f[i]);
}
}