1. 程式人生 > >『NOIP 2012』國王遊戲 (貪心 + 高精度)

『NOIP 2012』國王遊戲 (貪心 + 高精度)

.org include tchar memcpy 分別是 esp span 得獎 str

國王遊戲

題目描述

恰逢 \(H\) 國國慶,國王邀請 \(n\) 位大臣來玩一個有獎遊戲。首先,他讓每個大臣在左、右手上面分別寫下一個整數,國王自己也在左、右手上各寫一個整數。然後,讓這 \(n\) 位大臣排成一排,國王站在隊伍的最前面。排好隊後,所有的大臣都會獲得國王獎賞的若幹金幣,每位大臣獲得的金幣數分別是:排在該大臣前面的所有人的左手上的數的乘積除以他自己右手上的數,然後向下取整得到的結果。

國王不希望某一個大臣獲得特別多的獎賞,所以他想請你幫他重新安排一下隊伍的順序,使得獲得獎賞最多的大臣,所獲獎賞盡可能的少。註意,國王的位置始終在隊伍的最前面。



解題思路

非常巧妙的一道貪心題,思維能力太差的蒟蒻我還是得看題解 [害怕.jpg]

我們首先要發現一個非常玄學牛逼的一個貪心原則:左右手乘積小的人要放在前面?

我們一步步證明這個定理抄襲大佬的證明

假設我們現在有3個人,站成這樣的隊列:

1.

-----------隊首------------

\(A\) \(B\)

\(a_0\) \(b_0\)

\(a_1\) \(b_1\)

-----------隊尾------------

\(a\)代表左手,\(b\)代表右手,\(AB\)表示國王。

此時的\(ans1=max(\frac A {b_0} , \frac {A \times a_0}{b_1})\)

帶換一下\(ans1=max(k_1,k_2)\)

2.

-----------隊首------------

\(A\) \(B\)

\(a_1\) \(b_1\)

\(a_0\) \(b_0\)

-----------隊尾------------

此時的\(ans2=max(\frac A {b_1} , \frac {A \times a_1}{b_0})\)

帶換一下\(ans2=max(k_3,k_4)\)

顯然,我們發現\(k_1< k_4\),\(k_2 > k_3\)

我們直接欽定第一種方案是更優的。

那麽就會有\(ans1<ans2\),也就是\(k_4>k_2\)

代成原來的值就是$ \frac {{A} \times a_1}{b_0} > \frac {A \times a_0}{b_1}$

\(\frac{a_1}{b_0}>\frac{a_0}{b_1}\)

再次化簡就可以得到\(a_1 \times b_1 > a_0 \times a_1\)

這樣就可以看出來了,我們應該把\(a_i \times b_i\)小得人放在前邊。



代碼

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
const int maxn=1050;
const int wei=1e8;
struct nod{
    ll a,b,c;
};
int n;
ll A,B,cnt=0;
nod p[maxn];
ll mu[maxn],dd[maxn],tmp[maxn],ans[maxn],len,len_ans=0;
inline void read(register ll &x){
    x=0; register char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
}
inline bool cmp(nod x,nod y){
    return x.c<y.c;
}
inline void mul(ll x){
    for(register int i=1;i<=cnt;i++)mu[i]*=x;
    for(register int i=1;i<cnt;i++)
        mu[i+1]+=mu[i]/wei,mu[i]%=wei;
    while(mu[cnt]>=wei){
        mu[cnt+1]+=mu[cnt]/wei,mu[cnt]%=wei,cnt++;
    }
}
inline void div(ll x){
    len=0;
    memcpy(tmp,mu,sizeof(tmp));
    for(register int i=cnt;i>=1;i--){
        dd[i]=tmp[i]/x;
        if(dd[i]&&!len)len=i;
        tmp[i-1]+=(tmp[i]%x)*wei;
    }
}
inline void print(){
    printf("%lld",ans[len_ans]);
    for(register int i=len_ans-1;i>=1;i--){
        ll tmp=ans[i],cheng=1,j=1;
        for(;j<=8;j++){
            if(!(tmp/cheng))break;
            cheng*=10;
        }
        for(;j<=8;j++)putchar('0');
        if(ans[i])printf("%lld",ans[i]);
    }
}
inline void comp(){
    if(len<len_ans)return;
    if(len>len_ans)memcpy(ans,dd,sizeof(ans)),len_ans=len;
    else {
        for(register int i=len;i>=1;i--){
            if(dd[i]>ans[i]){
                memcpy(ans,dd,sizeof(ans));
                return ;
            }
        }
    }
}
int main(){
    scanf("%d",&n);
    read(A),read(B);
    for(register int i=1;i<=n;i++){
        read(p[i].a),read(p[i].b);
        p[i].c=p[i].a*p[i].b;
    }
    sort(p+1,p+n+1,cmp);
    while(A)mu[++cnt]=A%wei,A/=wei;
    for(register int i=1;i<=n;i++)
        div(p[i].b),comp(),mul(p[i].a);
    print();
}

『NOIP 2012』國王遊戲 (貪心 + 高精度)