NOIP2012提高组Day1T2 - 国王游戏

版权声明:转载请注明出处 https://blog.csdn.net/weixin_42557561/article/details/83830191

国王游戏

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

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

输出
输出只有一行,包含一个整数,表示重新排列后的队伍中获奖赏最多的大臣所获得的金币数

样例输入
3
1 1
2 3
7 4
4 6
样例输出
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。


Analysis

啊啊。高精度又写炸了,我可能和它不熟,要多练啊!!万一NOIP考到了呢??
其实这道题不算难,结论也很好推
就是根据数据范围发现连乘起来只能用高精度

贪心策略+交换相邻法
如果现在有两个大臣 i , j i,j ,什么时候 i 排在 j 前面会使答案更优?
1 i 1 1到i-1 的大臣(包括King)的左手的数字连乘起来为 x x
C i Ci 表示第 i 个大臣能拿到的金币数
则当i排在前面的时候 C i = x b i Ci=\frac{x}{b_i} C j = x a i b j Cj=\frac{x*a_i}{b_j}
j排在前面的时候 C i = x a j b i Ci=\frac{x*a_j}{b_i} C j = x b j Cj=\frac{x*}{b_j}
取一下max,再比较一下,就会发现
a i b i &lt; a j b j a_i*b_i&lt;a_j*b_j 的时候,i 在前面会更优

然后就排个序,高精度瞎搞一下


Code

#include<bits/stdc++.h>
#define in read()
#define N 50009
#define ll long long
using namespace std;
inline int read(){
	char ch;int f=1,res=0;
	while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
	while(ch>='0'&&ch<='9'){
		res=(res<<3)+(res<<1)+ch-'0';
		ch=getchar();
	}
	return f==1?res:-res;
}
int n;
struct node{ll a,b;}p[N];
inline bool cmp(const node &x,const node &y){return x.a*x.b<y.a*y.b;}
struct big{
	ll a[5000];
	int len;
	big(){	len=1;memset(a,0,sizeof(a));	}
	big(ll a){*this=a;} 
	big operator = (ll x){
		len=0;
		if(!x) len=1;
		while(x){a[++len]=x%10;x/=10;}
		return *this;
	}
	big operator *(big y){
		big c;
		c.len=len+y.len-1;
		for(int i=1;i<=len;++i)
			for(int j=1;j<=y.len;++j)
				c.a[i+j-1]+=a[i]*y.a[j];
		for(int i=1;i<=c.len;++i){
			if(c.a[i]>10){
				c.a[i+1]+=c.a[i]/10;
				c.a[i]%=10;
			}
		}
		int &l=c.len;
		while(c.a[l+1]) ++l,c.a[l+1]+=c.a[l]/10,c.a[l]%=10;//仍然要考虑进位u 
		return c;
	}
	big operator /(int y){//高精度除以单精度 
		int x=0;
		big res;res.len=len;
		for(int i=len;i>=1;--i){
			res.a[i]=(x*1ll*10+a[i])/y;
			x=(x*1ll*10+a[i])%y;
		}
		int &l=res.len; 
		while(!res.a[l]&&l) l--;
		return res;
	}
}mx,mul;
big Max(big x,big y){
	if(x.len>y.len) return x;
	if(x.len<y.len) return y;
	for(int i=x.len;i>=1;--i){
		if(x.a[i]>y.a[i]) return x;
		if(x.a[i]<y.a[i]) return y;
	}
	return x;
}
int main(){
	n=in;
	p[0].a=in;p[0].b=in;
	for(int i=1;i<=n;++i){p[i].a=in;p[i].b=in;}
	sort(p+1,p+n+1,cmp);
	mx=0;mul=p[0].a;
	for(int i=1;i<=n;++i){
		big tmp;
		tmp=mul/p[i].b;
		mx=Max(mx,tmp);
		big hh(p[i].a);//如果你在一边定义一边=,就相当于是在初始化,而不是赋值 
		mul=mul*hh;
	}
	for(int i=mx.len;i>=1;--i) cout<<mx.a[i];
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_42557561/article/details/83830191