P1080 国王游戏

国王游戏

恰逢 H国国庆,国王邀请n 位大臣来玩一个有奖游戏。首先,他让每个大臣在左、右手上面分别写下一个整数,国王自己也在左、右手上各写一个整数。然后,让这 n 位大臣排成一排,国王站在队伍的最前面。排好队后,所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。
国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣,所获奖赏尽可能的少。注意,国王的位置始终在队伍的最前面。

输入格式
第一行包含一个整数n ,表示大臣的人数。

第二行包含两个整数 a和 b,之间用一个空格隔开,分别表示国王左手和右手上的整数。

接下来 n行,每行包含两个整数a 和 b,之间用一个空格隔开,分别表示每个大臣左手和右手上的整数。

输出格式
一个整数,表示重新排列后的队伍中获奖赏最多的大臣所获得的金币数。

输入输出样例
输入 #1
3
1 1
2 3
7 4
4 6
输出 #1
2

说明/提示
【输入输出样例说明】
按 1、2、3 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2;
按 1、3、2 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2;
按 2、1、3 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2;
按 2、3、1 这样排列队伍,获得奖赏最多的大臣所获得金币数为 9;
按 3、1、2 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2;
按 3、2、1 这样排列队伍,获得奖赏最多的大臣所获得金币数为 9。
因此,奖赏最多的大臣最少获得 2个金币,答案输出 2。

【数据范围】
对于 20%的数据,有 1≤n≤10,0<a,b<8;
对于 40%的数据,有 1≤n≤20,0<a,b<8;
对于 60%的数据,有 1≤n≤100;
对于 60%的数据,保证答案不超过 10^9;
对于 100%的数据,有 1≤n≤1,000,0<a,b<10000。

分析

这道题目洛谷官网后面有题解,可参考国王游戏题解,自己还是证明一下。
首先可以对任意两个点p1、p2进行分析。

成员这段区间(点)的大小这段区间(点)的大小
一段区间X1Y1
p1a1b1
一段区间X2Y2
p2a2b2

此时有:
大臣p1的金币数量为 X1/b1;
大臣p2的金币数量为 X1╳X2╳a1/b2;
获得的奖赏最多的金币数量为ans1=max( X1/b1X1╳X2╳a1/b2);

然后将p1和p2大臣的位置进行互换,那么有

成员这段区间(点)的大小这段区间(点)的大小
一段区间X1Y1
p2a2b2
一段区间X2Y2
p1a1b1

此时有:
大臣p1的金币数量为 X1╳X2╳a2/b1;
大臣p2的金币数量为 X1/b2;
获得的奖赏最多的金币数量为ans2=max( X1╳X2╳a2/b1X1/b2);

那么很明显有X1╳X2╳a2/b1 > X1/b1X1╳X2╳a1/b2 > X1/b2
所以在这两种情况两位大臣所能获得的奖赏最多的最少金币数量为ans=min(ans1ans2)=max( X1╳X2╳a1/b2X1╳X2╳a2/b1);

如果ans1<ans2,那么有 X1╳X2╳a1/b2 < X1╳X2╳a2/b1,即 a1╳b1 < a2╳b2.
所以将ai╳bi 较小的时候,获得ans较小,即按照ai╳bi 的排序即可得出结果,注意不要忘记高精度乘法和除法~

代码如下

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
const int mx=1e4+10;
int sum[mx],ans[mx],maxn[mx];
int n,lens=1,lenm=1,lena=1;//首先让长度为1

struct node{
  ll a,b;
  bool operator <(const node x) const{
   return a*b<x.a*x.b;
  }
}s[mx];

void mul(ll x)//高精度乘法 
{
	int tmp=0;
	for(int i=1;i<=lens;i++) 
	  sum[i]*=x;
	for(int i=1;i<=lens;i++)//从低位开始进位 
	{
		tmp+=sum[i];
		sum[i]=tmp%10;
		tmp/=10;
	}
	while(tmp!=0)//如果最后可以进位 
	{
		lens++;
		sum[lens]=tmp%10;
		tmp/=10;
	}
}

void div(ll x)
{
   memset(ans,0,sizeof(ans));
   lena=lens;//暂时过来
   int tmp=0;
   for(int i=lena;i>=1;i--)
   {
      tmp*=10;
      tmp+=sum[i];
      if(tmp>=x)
      {
        ans[i]=tmp/x;
	tmp%=x;
       }
   }
   while(ans[lena]==0)
   {
   	  if(lena==1)
   	  break;
   	  lena--;
   }
}

void maxx()
{
	if(lena>lenm)
	{
		for(int i=1;i<=lena;i++)
		 maxn[i]=ans[i];
		lenm=lena;
	}
	else if(lena==lenm)
	{
		for(int i=lena;i>=1;i--)
		 if(maxn[i]<ans[i])
		 {
		 	for(int j=1;j<=lena;j++)
		 	  maxn[j]=ans[j];
		 	break;
		 }
	}
}

int main(){
	int n;
	scanf("%d",&n);
	scanf("%lld%lld",&s[0].a,&s[0].b);
	for(int i=1;i<=n;i++)
	scanf("%lld%lld",&s[i].a,&s[i].b);
    
        sort(s+1,s+1+n);//按照ai*bi排序
        sum[1]=maxn[1]=1;//初始化金币数量为1
        for(int i=1;i<=n;i++)//对于每个大臣已经排好位置,接下来暴力搜索
        {
    	  mul(s[i-1].a);
    	  div(s[i].b);
    	  maxx();
	}
	
	for(int i=lenm;i>=1;i--)
	printf("%lld",maxn[i]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值