国王游戏 2012NOIP全国联赛提高组

18 篇文章 1 订阅
11 篇文章 0 订阅

题目描述 Description

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

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

输入描述 Input Description

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

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

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

输出描述 Output Description

输出只有一行,包含一个整数,表示重新排列后的队伍中获奖赏最多的大臣所获得的

金币数。

样例输入 Sample Input

3
1 1
2 3
7 4
4 6

样例输出 Sample Output

2

数据范围及提示 Data Size & Hint

【输入输出样例说明】
按 1、2、3号大臣这样排列队伍,获得奖赏最多的大臣所获得金币数为 2;
按 1、3、2这样排列队伍,获得奖赏最多的大臣所获得金币数为2;
按 2、1、3这样排列队伍,获得奖赏最多的大臣所获得金币数为 2;
按 2、3、1这样排列队伍,获得奖赏最多的大臣所获得金币数为 9;
按 3、1、2这样排列队伍,获得奖赏最多的大臣所获得金币数为 2;
按 3、2、1这样排列队伍,获得奖赏最多的大臣所获得金币数为 9。
因此,奖赏最多的大臣最少获得 2 个金币,答案输出 2。

【数据范围】

对于20%的数据,有1≤ n≤ 10,0 < a、b < 8;
对于40%的数据,有1≤ n≤20,0 < a、b < 8;
对于60%的数据,有1≤ n≤100;
对于60%的数据,保证答案不超过 10^9;
对于100%的数据,有 1 ≤ n ≤1,000,0 < a、b < 10000。

思路

贪心+sort+高精单精。

第一次做时,我就是奔着前60%去的,只拿了50分,(恶心的高精)
设i之前的左手之积为X,对于i有左右手Li Ri 对于排在其后的j有左右手Lj Rj 当满足(X*Li)/Rj >(X*Lj)/Ri即满足Li*Ri>Lj*Rj时交换ij的位置显然更优,将数据LR之积递增排序就是最优方案,X会很大所以用到高精。

代码

#include<iostream> 
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
#define ll long long
const int maxn=5007;
using namespace std;
ll i,j,k,n,m,yi,er,r,mid,l,t;
int ans[maxn],ans1[maxn],b[maxn];
char s[maxn],st[maxn];
struct node{
    ll a,b,c;
}a[maxn];
bool cmp(node x,node y){
    return x.c<y.c;
}
void cheng(ll x){
    memset(b,0,sizeof(b));
    ll i,j,k,l,o=0;
    for(int i=1;i<=ans1[0];i++){
        b[i]=b[i]+ans1[i]*x+o;
        b[i+1]+=b[i]/10;
        b[i]=b[i]%10;
    }
    for(b[0]=ans1[0];b[b[0]+1];){
        b[++b[0]+1]+=b[b[0]]/10;
        b[b[0]]=b[b[0]]%10;
    }
    for(int i=0;i<=maxn;i++) ans1[i]=b[i];
}
void chu(ll x){
    ll i,j,k,o=0;
    memset(b,0,sizeof(b));
    for(int i=ans1[0];i>=1;i--){
        o=o*10+ans1[i];
        if(o>=x){
            if(b[0]==0) b[0]=i;
            b[i]=o/x;
            o=o%x;
        }
    }
}
void bijiao(){
    ll i,j,k,l;
    if(b[0]>ans[0]){
        for(int i=0;i<=maxn;i++) ans[i]=b[i];
    }
    else if(b[0]==ans[0]){
        for(int i=ans[0];i>=1;i--){
            if(b[i]>ans[i]){
                for(int j=0;j<=maxn;j++) ans[j]=b[j];
                return;
            }
        }
    }
}
int main(){
    scanf("%d",&n);
    scanf("%s",s+1);
    for(int i=strlen(s+1);i>=1;i--)ans1[++ans1[0]]=s[i]-'0';
    scanf("%d",&er);
    t=yi;
    for(int i=1;i<=n;i++){
        scanf("%lld%lld",&a[i].a,&a[i].b);
        a[i].c=a[i].a*a[i].b;
    }
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=n;i++){
        chu(a[i].b);
        bijiao();
        cheng(a[i].a); 
    }
    for(int i=ans[0];i>=1;i--)printf("%d",ans[i]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值