【jzoj3100】【NOIP2012提高组】【国王游戏】【贪心】【高精度】

19 篇文章 0 订阅

题目大意

恰逢H国国庆,国王邀请n位大臣来玩一个有奖游戏。首先,他让每个大臣在左、右手上面分别写下一个整数,国王自己也在左、右手上各写一个整数。然后,让这n位大臣排成一排,国王站在队伍的最前面。排好队后,所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。 国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣,所获奖赏尽可能的少。注意,国王的位置始终在队伍的最前面。

解题思路

写出函数后发现可以写成偏序关系,这样就可以贪心,但是数比较大,需要使用高精度。

code

#include<set>
#include<queue>
#include<cmath>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a>b)?b:a)
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
using namespace std;

typedef struct{int x,y;}note;
int const oo=2147483647;
int const maxn=3000000,mo=10000;
int n,ans[maxn+10],sum[maxn+10],tmp[maxn+10],anss[10];
struct rec{
    int a,b;
    friend bool operator<(rec x,rec y){
        return x.a*x.b<y.a*y.b;
    }
};
rec a[maxn+10];
void mult(int v){
    fo(i,1,sum[0])
        sum[i]=sum[i]*v;
    fo(i,1,sum[0]){
        sum[i+1]+=sum[i]/mo;
        sum[i]%=mo;
    }
    for(;sum[sum[0]+1];sum[0]++);
}
void div(int v){
    fo(i,0,sum[0])tmp[i]=sum[i];
    fd(i,tmp[0],2){
        tmp[i-1]+=tmp[i]%v*mo;
        tmp[i]/=v;
    }
    tmp[1]/=v;
    fo(i,1,tmp[0]){
        tmp[i+1]+=tmp[i]/mo;
        tmp[i]%=mo;
    }
    for(;tmp[0]&&(!tmp[tmp[0]]);tmp[0]--);
}
void maxx(){
    if(ans[0]>tmp[0])return;
    int flag=0;
    if(ans[0]<tmp[0])flag=1;
    else{
        fd(i,ans[0],1)
            if(ans[i]>tmp[i])break;
            else if(ans[i]<tmp[i]){flag=1;break;}
    }
    if(flag)fo(i,0,tmp[0])ans[i]=tmp[i];
}
int main(){
    freopen("d.in","r",stdin);
    freopen("d.out","w",stdout);
    scanf("%d",&n);
    fo(i,0,n)scanf("%d%d",&a[i].a,&a[i].b);
    sort(a+1,a+n+1);
    //fo(i,0,n)printf("%d%d\n",a[i].a,a[i].b);
    sum[0]=sum[1]=1;
    mult(a[0].a);
    fo(i,1,n){
        div(a[i].b);
        maxx();
        mult(a[i].a);
    }
    fd(i,ans[0],1){
        fo(j,1,4){
            anss[j]=ans[i]%10;
            ans[i]/=10;
        }
        anss[0]=4;
        if(i==ans[0]){
            for(;!anss[anss[0]];anss[0]--);
        }
        fd(j,anss[0],1)
            printf("%d",anss[j]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值