• LuoguP1080 国王游戏


    Description

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

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

    Input

    第一行包含一个整数 (n) ((1leq nleq10000)) ,表示大臣的人数。

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

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

    Output

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

    Example

    Input Output
    3
    1 1
    2 3
    7 4
    4 6
    2

    Solution

    考虑:若第 (k) 个大臣与第 (k+1) 个大臣交换位置后,两者间获得的较多金币的一方的所获金币数减少。

    设:排在第 (k) 个大臣前面的所有人的左手上的数的乘积为 (p)(a_i)(b_i) 分别表示第 (i) 个大臣左手和右手上的整数,

    则有 (max(frac{p}{b_{k+1}},frac{p imes a_{k+1}}{b_k})<max(frac{p}{b_k},frac{p imes a_k}{b_{k+1}}))

    显然有 (frac{p}{b_{k+1}}leqfrac{p imes a_k}{b_{k+1}})(frac{p imes a_{k+1}}{b_k}geqfrac{p}{b_k})

    则必有 (frac{p imes a_{k+1}}{b_k}<frac{p imes a_k}{b_{k+1}})

    亦即 (a_{k+1} imes b_{k+1}<a_k imes b_k)

    显然这是一个偏序关系,于是我们可以采用贪心的策略,按该偏序关系,以 (a_i imes b_i) 为关键字从小到大排序,再遍历所有大臣求最大的获得金币数即可。注意,金币数的数字很大,需要开高精度。


    Code

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef pair<int,int> pii;
    
    const int n_size=1e4+5;
    const int bit_size=40005;
    
    int n,p[bit_size]={1,1},ans[bit_size],tmp[bit_size];
    pii h[n_size];
    
    bool cmp(pii &a,pii &b);
    void mul(int x);
    void div(int x);
    void update(void);
    bool is_smaller(void);
    
    int main(void){
        scanf("%d",&n);
        for(int i=0;i<=n;i++)   scanf("%d%d",&h[i].first,&h[i].second);
        sort(h+1,h+n+1,cmp);
        for(int i=1;i<=n;i++){
            mul(h[i-1].first);
            div(h[i].second);
            update();
        }
        for(int i=ans[0];i>0;i--)  printf("%d",ans[i]);
        return 0;
    }
    
    inline bool cmp(pii &a,pii &b){
        return a.first*a.second<b.first*b.second;
    }
    
    void mul(int x){
        for(int i=1;i<=p[0];i++)    p[i]*=x;
        for(int i=1;i<=p[0];i++){
            p[i+1]+=p[i]/10;
            p[i]%=10;
        }
        for(int i=p[p[0]+1];i>0;i/=10)  p[++p[0]]=i%10;
    }
    
    void div(int x){
        memset(tmp,0,sizeof(tmp));
        int rmd=0;
        for(int i=p[0];i>0;i--){
            (rmd*=10)+=p[i];
            tmp[i]=rmd/x;
            if(tmp[0]==0&&tmp[i]>0) tmp[0]=i;
            rmd%=x;
        }
    }
    
    inline void update(void){
        if(is_smaller()==true)  memcpy(ans,tmp,sizeof(tmp));
    }
    
    bool is_smaller(void){
        if(ans[0]<tmp[0])   return true;
        if(ans[0]>tmp[0])   return false;
        for(int i=ans[0];i>0;i--)
            if(ans[i]<tmp[i])   return true;
            else if(ans[i]>tmp[i])  return false;
        return false;
    }
    
  • 相关阅读:
    使用Hibernate实现简单的增、改、删、查操作
    Hibernate 配置
    Win7/8下Oracle的安装
    Android从相册获取图片
    Android图片缓存分析(一)
    TextView淡入淡出效果
    Android动画全解
    ListView的getChildAt(i)方法
    AIDL小记
    自定义SeekBar的Thumb不对齐的解决方法。
  • 原文地址:https://www.cnblogs.com/MakiseVon/p/10594790.html
Copyright © 2020-2023  润新知