[NOIp2012] 国王游戏

类型:数学+贪心

传送门:>Here<

题意:有$N$个大臣,每个大臣的左手写着$a$,右手写着$b$。一个大臣得到的金币为所有排在他前面的大臣左手写的数字的乘积除以他自己右手的数字。问如何排列大臣们的顺序,使得到金币最多那个大臣得到的最少

解题思路

由于乘法交换律,一个大臣得到的金币取决于他前面有哪几个大臣,而不关心他前面大臣的排列顺序。也就是说如果调换相邻两个大臣的位置,则得到金币数量会改变的只有这两个被调换的人。因此我们可以通过不断调换相邻的两个人来使答案变小,直到最优

由此,我们只需要考虑两个大臣的情况。由于只有两个大臣,一共只能有2种情况。设目前考虑大臣$i$和$i+1$,设$i$之前所有大臣左手上数字的乘积为$tot$,则有两种情况$$ans1 = Max\{\dfrac{tot}{b_i},\dfrac{tot*a_i}{b_{i+1}}\}, ans2=Max\{\dfrac{tot}{b_{i+1}},\dfrac{tot*a_{i+1}}{b_{i}}\}$$不妨设为$$ans1=Max\{k_1,k_2\}, ans2=Max\{k_3,k_4\}$$

显然$$k_1<k_4, k_2>k_3$$

当$a_i*b_i<a_{i+1}*b_{i+1}$时$$\dfrac{a_i}{b_{i+1}}<\dfrac{a_{i+1}}{b_i}$$同时乘以$tot$得$$\dfrac{tot*a_i}{b_{i+1}}<\dfrac{tot*a_{i+1}}{b_i}$$也就是$$k_2<k_4$$由于$k_1<k_4$,故$$ans1<ans2$$

因此我们得到结论,只有当满足$a_i*b_i<a_{i+1}*b_{i+1}$,第$i$位大臣排在前面才会更优

因此我们以$a_i*b_i$为关键从小到大排序求解即可

Code

压位高精

/*This Program is written by QiXingZhi*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector> 
#include <cassert>
#include <iostream>
#include <string>
using namespace std;  
  
#define LL long long
#define maxn 1010
#define base 10000
struct Bigint{
    int c[2020],len;
    Bigint(){memset(c,0,sizeof(c));len=1;}
    void Zero(){while(c[len]==0&&len>1)len--;}
    Bigint Write(char* s){
        memset(c,0,sizeof(c));len=1;
        int k=1,ll=strlen(s);
        for(int i=ll-1;i>=0;i--){
            c[len]+=(s[i]-'0')*k;
            k*=10;
            if(k==base){
                k=1,len++;
            }
        }
        Zero();
        return *this;
    }
    void read(){
        char s[10020];
        scanf("%s",s);
        Write(s);
    }
    void Print(){
        Zero();
        printf("%d",c[len]);
        for(int i=len-1;i>=1;i--){
            printf("%04d",c[i]);
        }
    }
    bool operator >(Bigint& b){
        Zero();b.Zero();
        if(len!=b.len)return  len>b.len;
        for(int i=len;i>=1;i--){
            if(c[i]!=b.c[i])return c[i]>b.c[i];
        }
        return false;
    }
    bool operator <(Bigint& b){
        Zero();b.Zero();
        if(len!=b.len)return  len<b.len;
        for(int i=len;i>=1;i--){
            if(c[i]!=b.c[i])return c[i]<b.c[i];
        }
        return false;
    }
    Bigint operator = (const int& b){
        memset(c,0,sizeof(c)),len=1;
        char s[10020];
        sprintf(s,"%d",b);
        Write(s);
        return *this;
    }
    Bigint operator *(const int & b){
        Bigint r;
        r.len=len+4;
        for(int i=1;i<=r.len;i++){
            r.c[i]+=c[i]*b;
        }
        for(int i=1;i<=r.len;i++){
            r.c[i+1]+=r.c[i]/base;
            r.c[i]%=base;
        }
        r.Zero();
        return r;
    }
    Bigint operator / (const int& b){
        Bigint r,k;
        k=*this;
        r.len=len+1;
        for(int i=len;i>=1;i--){
            r.c[i]=k.c[i]/b;
            if(i!=1)k.c[i-1]+=(k.c[i]%b*base);
            k.c[i]/=b;
        }
        r.Zero();
        return  r;
    }
}; 
struct People{
    int a,b;
    Bigint mul;
}p[1010];
int N,A,B;
Bigint ans,tot,x,y;
inline bool cmp(const People& a, const People& b){
    x = a.mul, y = b.mul;
    return x < y;
}
int main(){
    scanf("%d",&N);
    scanf("%d %d",&A,&B);
    for(int i = 1; i <= N; ++i){
        scanf("%d %d",&p[i].a,&p[i].b);
        p[i].mul = p[i].a * p[i].b;
    }
    sort(p+1,p+N+1,cmp);
    ans = 0;
    tot = A;
    for(int i = 1; i <= N; ++i){
        if(tot/p[i].b > ans){
            ans = tot/p[i].b;
        }
        tot = tot * p[i].a;
    }
    ans.Print();
    return 0;
} 

猜你喜欢

转载自www.cnblogs.com/qixingzhi/p/9483805.html