P1080 国王游戏

链接

P1080 国王游戏

思路

首先我们先思考一下当只有两个大臣的时候怎么做(当题目没有思路的时候,先考虑数据范围小的情况往往是有帮助的)。 如果国王左手上的数是 \(a_0\),两个大臣左右手上的数是\(a_1,b_1,a_2,b_2\);那么有两种排法: 第一个大臣排在前面,那么第一个大臣获得 \(a_0 / b_1\) 奖赏,第二个获得 \(a_0a_1 / b_2\) 奖赏,奖赏最多的大臣获得的奖赏就是 \(max(a_0 / b_1, a_0a_1 / b_2)\)。 同样,如果第二个大臣排在前面,答案就是\(max(a_0 / b_1, a_0a_1 / b_2)\)

比较 \(ans_1=max(a_0 / b_1, a_0a_1 / b_2)\)\(ans_2=max(a_0 / b_1, a_0a_1 / b_2)\),可以写成 \(ans_1=a_0 max(b_2,a_1\cdot b_1) / b_1\cdot b_2 ans_2=a_0 max(b_1,a_2\cdot b_2) / b_1\cdot b_2\) 可以想象,如果 \(a_1\cdot b_1 ≤ a_2\cdot b_2,\)那么 $ans_1 $肯定更小,因为这种情况下 $a_1\cdot b_1 ≤ a_2\cdot b_2 $而 \(b_2 ≤ a_2\cdot b_2\),所以 \(max(b_2,a_1\cdot b_1) ≤ a_2\cdot b_2 ≤ max(b_1,a_2\cdot b_2)\) 同理,如果$ a_1\cdot b_1 > a_2\cdot b_2\(那么\) ans_2 \(更小。 于是我们得到一个结论:只有两个人时,把\) a_i \cdot b_i $更小那个放到前面一定更优。

当有更多大臣的时候呢? 考虑最优解满足什么性质。如果我们交换最优解中两个相邻的大臣,那么他们前面的大臣得到的奖赏显然不受影响;而他们后面的大臣也不受影响。(想一想,为什么) 那么把这两个大臣单独拎出来,根据之前的结论,最优解中一定是 ab 较小的放到前面。 这样的话,我们得出结论:最优解中相邻两个大臣,前面的 ab 一定更小。否则可以交换相邻的大臣使得答案更小。

于是最优解肯定是按大臣的 $a\cdot b \(排序后的结果。所以将大臣按\) a\cdot b $排好序,计算每个大臣的奖赏就可以了(这题代码难点在于高精度) 通过这道题我们看出一种贪心的分析方式,它尤其适用于“将若干个物品重新排列使得___最小/最大”的问题: 假设我们有一组解,考虑如何调整能使它更优(对于重新排列,一般是交换相邻物品); 最优解一定不能调整。

以来来自《noip杂题选讲 by rqy》

代码

主要是高精度(

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<string>
#include<cstring>
using namespace std;
struct num {
	int len,s[10005];//len为数字位数,s数组为每一位上的数字
	num(int a=0) { //构造函数
		len=0;
		memset(s,0,sizeof(s));
		while(a) {
			len++;
			s[len]=a%10;
			a/=10;
		}
	}
	num operator * (const num &a) const {
		num c;
		int x;
		for(int i=1; i<=a.len; ++i) {
			x=0;
			for(int j=1; j<=len; ++j) {
				c.s[i+j-1]+=a.s[i]*s[j]+x;
				x=c.s[i+j-1]/10;
				c.s[i+j-1]%=10;
			}
			c.s[i+len]=x;
		}
		c.len=a.len+len;
		while(!c.s[c.len] && c.len!=1) c.len--;
		return c;
	}
	num operator / (const int &a) const { //重载整除运算(高精)
		num c;
		int x=0;
		c.len=len;
		for(int i=c.len; i>=1; --i) {
			x=x*10+s[i];
			c.s[i]=x/a;
			x%=a;
		}
		while(!c.s[c.len] && c.len!=1) c.len--;
		return c;
	}
	bool operator < (const num & x) const {//重载'<'(高精比较大小),max函数中要用
		if(len!=x.len) return len<x.len;
		for(int i=len; i>0; i--)
			if(s[i]!=x.s[i])
				return s[i]<x.s[i];
		return 0;
	}
};
struct node { //表示大臣的结构体
	int a,b,c;
} p[10005];
int cmp(node a,node b)
{
	return a.c<b.c;
}
int n;
int main() {
	cin>>n;
	for(int i=0; i<=n; ++i) {
		cin>>p[i].a>>p[i].b;
		p[i].c=p[i].a*p[i].b;
	}
	num sum(p[0].a),ans;
	sort(p+1,p+n+1,cmp);
	for(int i=1; i<=n; ++i) {
		ans=max(ans,sum/p[i].b);
		sum=sum*p[i].a;
	}
	for(int i=ans.len; i>=1; i--)
		cout<<ans.s[i];
	return 0;
}
posted @ 2019-08-04 10:53  pyyyyyy  阅读(248)  评论(1编辑  收藏  举报