题目:
题解:
首先证明一些东西
可知相邻的两个交换位置,只对这两个有影响。我们设i和j,使j站在i的后面金币数保持最小。令i前面所有人左手乘积为Q,对于j而言,想要使得j的金钱尽量小,必须满足Q*ai/bj<Q*aj/bi 然后化简,两边消掉Q,同时乘以bj和bi 可知此时ai*bi<aj*bj
那我们先按照这个东西排序,那么这是所有排列中最小的一种。
然后要做的就是看看这种排列中,大臣们拿的最多的金币是多少,需要运用高精度!!!因为a和b的范围,我们就压5位.
代码:
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
struct hh{int a,b,c;}c[1005];
int sum[2000],divv[2000],ans[2000];
int cmp(hh a,hh b){return a.c<b.c;}
bool compare()
{
bool fff=false;
if (divv[0]>ans[0]) return 1;
for (int i=divv[0];i>0;i--)
if (divv[i]>ans[i]) return 1;
return 0;
}
int main()
{
int n,i,j;
scanf("%d",&n);
for (i=0;i<=n;i++)
scanf("%d%d",&c[i].a,&c[i].b),c[i].c=c[i].a*c[i].b;
sort(c+1,c+n+1,cmp);
sum[0]=1; sum[1]=1;
for (i=1;i<=n;i++)
{
int x=0;
for (j=1;j<=sum[0];j++)
{
sum[j]=sum[j]*c[i-1].a+x;
x=sum[j]/100000;
sum[j]%=100000;
}
if (x>0){sum[0]++; sum[sum[0]]=x;}
x=0;
memset(divv,0,sizeof(divv));
for (j=sum[0];j>0;j--)
{
divv[j]=(x*100000+sum[j])/c[i].b;
x=(x*100000+sum[j])%c[i].b;
}
divv[0]=sum[0];
while (divv[divv[0]]==0) divv[0]--;
if (compare()) for (j=0;j<=divv[0];j++) ans[j]=divv[j];
}
printf("%d",ans[ans[0]]);
for (i=ans[0]-1;i>0;i--)
{
printf("%d",ans[i]/10000);
printf("%d",ans[i]/1000%10);
printf("%d",ans[i]/100%10);
printf("%d",ans[i]/10%10);
printf("%d",ans[i]%10);
}
}