n+1个人排成一列,从2到n+1个人所获得的金币为前面所有人左手数字之和除以自己右手的数字。并对这n个人进行排列使得获得金币最多的人获得的金币尽可能的少。
输入:
第一行,输入n
接下来n+1行,每行两个数a,b,表示第i个人左手和右手的数字
输出:
获得的最少金币数
3
1 1
2 3
7 4
4 6
2
【输入输出样例说明】
按 11 、 22 、 33 这样排列队伍,获得奖赏最多的大臣所获得金币数为 22 ;
按 11 、 33 、 22 这样排列队伍,获得奖赏最多的大臣所获得金币数为 22 ;
按 22 、 11 、 33 这样排列队伍,获得奖赏最多的大臣所获得金币数为 22 ;
按 22 、 33 、 1 1 这样排列队伍,获得奖赏最多的大臣所获得金币数为 99 ;
按 33 、 11 、 2 2 这样排列队伍,获得奖赏最多的大臣所获得金币数为 22 ;
按 33 、 22 、 11 这样排列队伍,获得奖赏最多的大臣所获得金币数为 99 。
因此,奖赏最多的大臣最少获得 2 2 个金币,答案输出 22 。
【数据范围】
对于 20%的数据,有 1≤ n≤ 10,0 < a,b < 8,1≤n≤10,0 < a,b<8 ;
对于 40%的数据,有 1≤ n≤20,0 < a,b < 81≤n≤20,0 < a,b<8 ;
对于 60%的数据,有 1≤ n≤100,1≤n≤100;
对于 60%的数据,保证答案不超过 10^9;
对于 100%的数据,有 1 ≤ n ≤1,000,0 < a,b < 10000,1≤n≤1,000,0 < a,b < 10000
此处需要用到一些数学证明,先上结论最小的排列,是根据a*b降序排列后的数列。
证明如下
现在考虑相邻的两个人,设他们前面所有人的左手的乘积为k。
交换两人的位置会有两种不同的大小:
方案一:max{k/b1,k*a1/b2}
方案二:max{k/b2.k*a2/b1}
不妨设方案一 < 方案二
又因为k/b2 < k*a1/b2 ,k/b1 < k*a2/b1
所以k*a1/b2 < k*a2/b1
整理可得a1*b1 < a2*b2
(即当a1*b1>=a2*b2时,两人需要交换位置)
利用冒泡排序的思想,可以得到当ai*bi成升序排列时,最大金币数最小。
然后就只是高精乘低精和高精除低精。
下面附上代码一份:
#include
#include
#include
#include
using namespace std;
const int maxn=100010;
const int N=1001;
struct node
{
int a,b,mul;
}num[maxn];
int n;
bool cmp(node x,node y)
{
return x.mulint ret[N],ans[N];
int tmp[N],lt;
int lr,la;
bool check()
{
if(lt>la) return 1;
if(ltreturn 0;
for(int i=lt;i>=1;i--)
{
if(tmp[i]>ans[i]) return 1;
if(tmp[i]return 0;
}
return 0;
}
int main()
{
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
scanf("%d",&n);
for(int i=0;i<=n;i++)
{
scanf("%d%d",&num[i].a,&num[i].b);
num[i].mul=num[i].a*num[i].b;//提取关键字
}
sort(num+1,num+n+1,cmp);//关键字排序
ret[1]=num[0].a,lr=1,la=0;
for(int i=1;i<=n;i++)
{//高精乘除,ret累计乘,ans储存最佳答案,tmp计算第i个人(除去第一个人)所获得金币数
int a=num[i].a,b=num[i].b;
lt=lr;
for(int j=1;j<=lt;j++)
tmp[j]=ret[j];
for(int j=lt;j>=1;j--)
tmp[j-1]+=tmp[j]%b*10000,tmp[j]=tmp[j]/b;
while(tmp[lt]<=0) lt--;
if(check())
{
la=lt;
for(int j=1;j<=la;j++)
ans[j]=tmp[j];
}
for(int j=lr;j>=1;j--)
ret[j]*=a;
for(int j=1;j<=lr;j++)
ret[j+1]+=ret[j]/10000,ret[j]%=10000;
while(ret[lr+1]>0)
{
lr++;
ret[lr+1]+=ret[lr]/10000;
ret[lr]=ret[lr]%10000;
}
}
printf("%d",ans[la]);
for(int i=la-1;i>=1;i--)
printf("%04d",ans[i]);
return 0;
}