洛谷P1080 国王游戏--高精度

题目链接
https://www.luogu.org/problem/show?pid=P1080
题目描述

恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏。首先,他让每个大臣在左、右手上面分别写下一个整数,国王自己也在左、右手上各写一个整数。然后,让这 n 位大臣排成一排,国王站在队伍的最前面。排好队后,所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。

国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣,所获奖赏尽可能的少。注意,国王的位置始终在队伍的最前面。

输入输出格式
输入格式

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

输出格式

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

输入

3 
1 1 
2 3 
7 4 
4 6

输出

2

解题思路:
本题主要考察贪心和高精度。国王的位置始终是定的,根据大臣之间不同的排序决定最后拿到最多获赏的大臣尽可能的少,现在不妨假设相邻的第 i 和第 j 个大臣前面已经累积了 t o t a l ,若保证获奖时 i 得到的金币尽可能的少于 j 。即 t o t a l h a n d [ i ] . l / h a n d [ j ] . r <= t o t a l h a n d [ j ] . l / h a n d [ i ] . r
转化过来即是: h a n d [ i ] . l h a n d [ i ] . r <= h a n d [ j ] . l h a n d [ j ] . r
故直接对 h a n d 结构体按上述规则排序即可,同时连乘时需要高精度。
最后注意到金币最多的不一定是最后一个大臣,例如:

3
9999 1
1 1
1 1
1 9999  排序之后最后一名大臣得到金币不一定是最多的 

所以排序完成之后对每个大臣进行计算时,需要对最多的金币数量进行更新。

代码部分:

#include <iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
#define maxn 1000
struct hand{
    int l,r;
}ha[N];
bool cmp(hand &A,hand &B){
    return A.l*A.r<B.l*B.r;//升序,贪心的部分 
}
struct bignum{
    int digit[1000];//每个digit[i]最多表示一个四位数,如12345可记为digit[0]=1,digit[1]=2345,此时size=2; 
    int size ;

    void init(){
        for(int i=0;i<1000;i++)
            digit[i]=0;
        size=0; 
    }
    void set(int x){//12345
        init();
        do{
            digit[size++]=x%10000;
            x/=10000; 
        }while(x!=0);
    }

    void print(){
        for(int j=size-1;j>=0;j--){
            if(j==size-1)//最高位不一定刚好是4位数
                printf("%d",digit[j]);
            else
                printf("%04d",digit[j]);//输出digit[j](4位数),不足的用0填充
        }
        printf("\n");
    }
    bignum operator * (int &x){//高精度*低精度 
        bignum ans;
        ans.init();
        int carry=0;//进位 
        for(int i=0;i<size;i++){
            int tmp=x*digit[i]+carry;
            ans.digit[ans.size++]=tmp%10000;
            carry=tmp/10000;
        }
        if(carry){
            ans.digit[ans.size++]=carry;
        }
        return ans;
    }

    bignum operator / (int &x){//向下取整 ,高精度/低精度 
        bignum ans;
        ans.init();
        int remain=0;//余数
        for(int j=size-1;j>=0;j--){
            int tmp=digit[j]+remain*10000;
            ans.digit[j]=tmp/x;//最高位
            remain=tmp%x;
        } 
        ans.size=0;
        for(int j=0;j<maxn;j++){
            if(ans.digit[j]!=0)
                ans.size=j;//找到最高位 
        }
        ans.size++;
        return ans;
    }

    bool operator < (bignum &A){ //比较大小,找到金币最多的大臣 
        if(size<A.size)
            return true;
        else if(size>A.size)
            return false;
        else{
            int j=size-1;
            for(;j>=0;j--){
                if(digit[j]<A.digit[j])
                    return true;
                if(digit[j]>A.digit[j])
                    return false;
            }
            if(j==0)
                return false;
        }
    }
}a,b;

int main(){
    int n;
    scanf("%d",&n);
    for(int i=0;i<=n;i++)
        scanf("%d%d",&ha[i].l,&ha[i].r);
    sort(ha+1,ha+n+1,cmp);
    a.set(1);
    bignum maxv;//最后一名大臣得到金币不一定是最多的 
    maxv.set(0);
    for(int i=0;i<n;i++){
        a=a*ha[i].l;
        b=a/ha[i+1].r;
        if(maxv<b)
            maxv=b;
    }

    maxv.print(); 
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zhuixun_/article/details/81741821