zoukankan      html  css  js  c++  java
  • 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_1cdot b_1) / b_1cdot b_2 ans_2=a_0 max(b_1,a_2cdot b_2) / b_1cdot b_2) 可以想象,如果 (a_1cdot b_1 ≤ a_2cdot b_2,)那么 $ans_1 $肯定更小,因为这种情况下 $a_1cdot b_1 ≤ a_2cdot b_2 $而 (b_2 ≤ a_2cdot b_2),所以 (max(b_2,a_1cdot b_1) ≤ a_2cdot b_2 ≤ max(b_1,a_2cdot b_2)) 同理,如果$ a_1cdot b_1 > a_2cdot b_2(那么) ans_2 (更小。 于是我们得到一个结论:只有两个人时,把) a_i cdot b_i $更小那个放到前面一定更优。

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

    于是最优解肯定是按大臣的 $acdot b (排序后的结果。所以将大臣按) acdot 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;
    }
    
  • 相关阅读:
    1105 Spiral Matrix (25 分)螺旋矩阵
    1089 Insert or Merge (25 分)
    1044 Shopping in Mars (25 分)二分查找
    1068 Find More Coins (30 分)记忆化搜索
    1133 Splitting A Linked List (25 分)
    1145 Hashing
    1147 Heaps (30 分)
    1098 Insertion or Heap Sort (25 分)
    自测-3 数组元素循环右移问题 (20 分)
    自测-1 打印沙漏 (20 分)
  • 原文地址:https://www.cnblogs.com/pyyyyyy/p/11297511.html
Copyright © 2011-2022 走看看