P1080 [NOIP2012 提高组] 国王游戏-高精度+贪心+排序

[NOIP2012 提高组] 国王游戏

题目描述

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

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

输入格式

第一行包含一个整数 n n n,表示大臣的人数。

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

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

输出格式

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

样例 #1

样例输入 #1

3 
1 1 
2 3 
7 4 
4 6

样例输出 #1

2

这个题目我一边听课一边写,调试了很久
总算过了,可能代码很乱,但是过程中遇到的细节、问题都在代码中注释出来了

#include 
using namespace std;
#define de(x) cout<<x<<" ";
#define Pu puts("");
#define sf(x) scanf("%d",&x);
typedef long long ll;
const int N=1e5+10,mod=100003;
const int inf=0x3f3f3f3f;
struct E{
    ll u,v;
}s[N];
ll n,m,ans;
ll a,b;
ll w[N],tot;//fun1中得到的左手数乘积

ll sh[N],id;//fun2中得到的商
ll res[N],cnt;//结果,由sh得到
bool cmp(E a,E b){
    return a.v*a.u<b.v*b.u;
}
void fun1(ll x){
    ll t=0,tmp;
    for(int i=1;i<=tot;i++){
        tmp=(x*w[i]+t);
        w[i]=tmp%10;
        t=tmp/10;
    }
    while(t){
        w[++tot]=t%10;
        t/=10;
    }
}
void fun2(int x){
    ll t=0;
    id=0;
    if(x==1){//特殊情况:如果这个大臣右手数字为1,则用高精度得到的结果是错误的
    //应该直接把w赋值给sh 得到的结果恒等于
        for(int i=tot;i>=1;i--){
            sh[tot-i+1]=w[i];
        }
        id=tot;
    }else{
        int f=0;
         for(int i=tot;i>=1;i--){
            t=t*10+w[i];
            if(t>=x){
                sh[++id]=t/x;
                if(f==0) f=1;

                if(t%x==0){//特殊情况:注意0 比如100/10
                    int i_tmp=i-1;
                    while(w[i_tmp]==0&&i_tmp>=1){
                        sh[++id]=0;
                        i_tmp--;
                    }
                    i=i_tmp+1;
                }

                t=t%x;
            }else if(f==1){//注意这里:有可能某个位不能整除,需要后移
                sh[++id]=0;
            }
        }
        while(t>x){
            sh[++id]=t/x;
            t=t%x;
        }
    }
    if(id>cnt||(id==cnt&&res[1]<sh[1])){//是否更新答案
        for(int i=1;i<=id;i++){
            res[i]=sh[i];
        }
        cnt=id;
    }
}
int main(){
    cin>>n>>a>>b;
    for(int i=1;i<=n;i++){
        sf(s[i].u)sf(s[i].v)
    }
    sort(s+1,s+n+1,cmp);
    while(a){//把a放进w(乘积数组)中
        w[++tot]=a%10;
        a/=10;
    }
    for(int i=1;i<=n;i++){
        if(i>1) fun1(s[i-1].u);//第一个大臣不用乘以它前一个人左手的数字了
        //即是国王左手的数字
        fun2(s[i].v);
    }

    if(cnt==0){//特殊情况:都不满足
        printf("0\n");
        return 0;
    }
    for(int i=1;i<=cnt;i++){
        printf("%d",res[i]);
    }
    return 0;
}

你可能感兴趣的:(洛谷题单,游戏,算法,贪心算法)