zoukankan      html  css  js  c++  java
  • 洛谷 P1080 国王游戏 题解

    原题

    传送门

    思路

    分析

    我们先假设队伍如下:

    People left hand right hand
    Before (S_a)
    A (a_1) (b_1)
    B (a_2) (b_2)
    After (S_b)

    现在我们要交换A、B,队伍如下:

    People left hand right hand
    Before (S_a)
    B (a_2) (b_2)
    A (a_1) (b_1)
    After (S_b)

    我们可以发现:这样交换对于BeforeAfter部分的结果没有影响,只对AB 的部分结果有影响。
    对于交换前的答案:
    (ans1=max{dfrac{S_a}{b_1},dfrac{S_a imes a_1}{b_2}})
    对于交换后的答案:
    (ans2=max{dfrac{S_a}{b_2},dfrac{S_a imes a_2}{b_1}})
    我们知道,这些数都是大于等于(1)的正整数,于是:
    (dfrac{S_a imes a_1}{b_2} ge dfrac{S_a}{b_2})

    (dfrac{S_a imes a_2}{b_1} ge dfrac{S_a}{b_1})

    因此,当我们假定 (ans1 < ans2)时,一定是:
    (dfrac{S_a imes a_1}{b_2} < dfrac{S_a imes a_2}{b_1})
    化简得:
    (a_1 imes a_2 < b_1 imes b_2)

    算法

    显然,此关系满足传递性,即当
    (a_1 imes a_2 < b_1 imes b_2)
    (b_1 imes b_2 < c_1 imes c_2)
    有:
    (a_1 imes a_2 < c_1 imes c_2)
    因此,我们可以贪心,只要按此规则排序,再统计答案即可,注意要高精

    代码

    压位高精:

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    
    #define ll long long
    
    const int MAXN = 1010;
    const int base = 10000;
    
    int n;
    struct people{
    	int x,y;
    	bool operator < (const people &b ) const {
    		return (ll)x * y < (ll)b.x * b.y;
    	}
    }peo[MAXN];
    
    struct bignum{//only mul ,comp ans so on
    	int a[1020],len;
    	bignum() {//初始化
    		memset(a,0,sizeof(a));
    		len = 1;
    	}
    	void resize(){//限制位数
    		len = 1010;
    		for(int i = len - 1;i >= 0;i--)
    			if( a[i] > 0 ) { 
    				len = i + 1;
    				return;
    			}
    		len = 1;
    	}
    	bool operator < (const bignum &b) const{//比大小
    		if ( len != b.len) return len < b.len;
    		for(int i = len - 1 ;i >= 0 ;i--){
    			if(a[i] != b.a[i]) return a[i] < b.a[i];
    		}
    		return 0;
    	}
    	
    	bignum operator * (const int &b) const{ //乘法(高精乘int)
    		bignum c;
    		for(int i = 0; i < len ;i++){
    			c.a[i] += a[i] * b;
    			if( c.a[i] >= base) {
    				c.a[i+1] += c.a[i]/base;
    				c.a[i] %= base;
    			}
    		}
    		c.resize();
    		return c;
    	}
    	
    	bignum operator / (const int &b) const{//除法(高精除int)
    		ll temp = 0;
    		bignum c;
    		if( b == 0) {
    			printf("Error!");
    			return c;
    		}
    		for(int i = len -1;i >= 0;i--){
    			temp = temp * base + a[i];
    			if(temp >= b) {
    				c.a[i] = temp / b;
    				temp %= b;
    			}
    		}
    		c.resize();
    		return c;
    	}
    	
    	void print (){//输出
    		resize();
    		printf("%d",a[len-1]);
    		if ( len > 1) 
    		for(int i = len - 2;i >=0;i--){
    			printf("%04d",a[i]);
    		}
    		return;
    	}
    };
    int main (){
    	scanf("%d",&n);
    	for(int i = 0;i <= n;i++){
    		scanf("%d %d",&peo[i].x,&peo[i].y);
    	}
    	sort(peo+1,peo+n+1);
    	bignum ans,tot;
    	tot.a[0] = 1 ;
    	tot = tot * peo[0].x;
    	for(int i = 1;i <= n;i++){
    		bignum temp = tot / peo[i].y;
    		tot = tot * peo[i].x;
    		if( ans < temp ) ans = temp;
    	}
    	ans.print();
    	return 0;
    }
    

    反思总结

    应该是太久没写压位高精了,打错了INF回,我有几个出错的地方:

    1. resize() 函数里未在最后设置len=1 ,导致数为0时len很大
    2. resize() 函数里面把 return 写成break; ,导致每个被resize()的数的len=1
    3. base可以去1e5但只取了1e4
    4. print()函数里面输出记忆错误:
    printf("%4d",a[i]);
    

    显然,少了0
    5. *函数里面写成了:

    bignum operator * (const int &b) const{
    		bignum c;
    		for(int i = 0; i < len ;i++){
    			c.a[i] = a[i] * b;
    			if( c.a[i] >= base) {
    				c.a[i+1] += c.a[i]/base;
    				c.a[i] %= base;
    			}
    		}
    		c.resize();
    		return c;
    	}
    

    总的来说,我也要多练习压位高精……

  • 相关阅读:
    ModelState 错误信息输出
    c# 导入导出excel方法封装
    签名时出错: 未在路径 C:Program Files (x86)Microsoft SDKsWindowsv7.0Ain
    win 10 升级远程连接服务器 要求的函数不受支持
    请求被中止: 未能创建 SSL/TLS 安全通道
    访问iis 出现500.19错误
    ubuntu下交叉编译海思平台下的x264/x265
    C++编程规范
    C++入门--菱形继承与虚继承
    C++入门 --- 纯虚函数与抽象类
  • 原文地址:https://www.cnblogs.com/werner-yin/p/13276568.html
Copyright © 2011-2022 走看看