NOIP2012D1T2-国王的游戏

问题描述

恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏。首先,他让每个大臣在左、右手上面分别写下一个整数,国王自己也在左、右手上各写一个整数。然后,让这 n 位大臣排成一排,国王站在队伍的最前面。排好队后,所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。
国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣,所获奖赏尽可能的少。注意,国王的位置始终在队伍的最前面。
输入格式
第一行包含一个整数 n ,表示大臣的人数。
第二行包含两个整数 a 和 b ,之间用一个空格隔开,分别表示国王左手和右手上的整数。
接下来 n 行,每行包含两个整数 a 和 b ,之间用一个空格隔开,分别表示每个大臣左手和右手上的整数。
输出格式
一个整数,表示重新排列后的队伍中获奖赏最多的大臣所获得的金币数。
样例输入

3 
1 1 
2 3 
7 4 
4 6 

样例输入

2

思路分析

看到这道题的最大值最小我就又想到的DP…
发现dp连状态都定义不了…
于是就想到了二分答案
发现,答案不是单调的,于是二分答案也不行
……
当然,模拟肯定是GG
于是就想到了贪心,我们可以定义性价比这个概念b=r/l,为啥这么定义呢?
我也不知道…
但是我就这么写了程序..
过了第一个点…

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <map> 
using namespace std;
int l[10050],r[10050];
double b[10050];
int main(){
    int n,a,c;
    cin>>n;
    cin>>a>>c;
    for(int i=0;i<n;i++){
        cin>>l[i]>>r[i];
        b[i]=r[i]/l[i];
    }
    double maxn=-1;
    int cur;
    for(int i=0;i<n;i++){
        if(maxn<b[i]){
            maxn=max(b[i],maxn);
            cur=i;
        }
    }
    int ans=1;
    for(int i=0;i<n;i++)ans*=l[i];
    ans*=a;
    ans/=r[cur];
    ans/=l[cur];
    cout<<ans;
    return 0;
}

发现
性价比这个东西好像定义错了,因为求解过程是这个大臣前面的相乘/自己右手的
但是成绩最大的一定是除他以外所有的左手相乘/自己的右手,那么如果选左手最小的放最后那么他的右手有多大不一定
于是我们定义性价比=l*r
还有一个优点,ans=所有人的左手相乘除以性价比最大的人的性价比,除以性价比,相当于/l/r正好消了l;于是写出代码,但是只有10分

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int l[10050],r[10050];
int x[10050];
int main(){
    int a,b,n;
    cin>>n>>a>>b;
    for(int i=0;i<n;i++){
        cin>>l[i]>>r[i];
        x[i]=r[i]*l[i];
    }
    int tot=1;
    for(int i=0;i<n;i++)tot*=l[i];
    int maxn=-1;
    sort(x,x+n);

    cout<<tot/maxn;
    return 0;
}

想想为什么错了,性价比最高的大臣不一定是ans,所以我们应该吧性价比排队,然后,一个一个试,于是就有了60分代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 1015;
int n,m;
long long ans = 0,ccj = 0;

struct edge
{
    int l,r;
    long long cnt,cj;
}num[MAXN],gw;

bool cmp(edge a,edge b)
{
    return a.cj < b.cj;
}

int main()
{
    scanf("%d",&n);
    scanf("%d %d",&gw.l,&gw.r);
    gw.cj = gw.l * gw.r;
    for(int i = 1; i <= n; i ++)
    {
        scanf("%d %d",&num[i].l,&num[i].r);
        num[i].cj = num[i].l * num[i].r;
    }
    sort(num + 1,num + 1 + n,cmp);
    num[0].l = gw.l;num[0].r = gw.r;
    num[0].cj = gw.cj;ccj = num[0].l;
    for(int i = 1; i <= n; i ++)
    {
        num[i].cnt = ccj / num[i].r;
        ccj *= num[i].l;
    }   
    for(int i = 1; i <= n; i ++)
        ans = max(ans,num[i].cnt);
    printf("%lld\n",ans);
    return 0;   
}

还有什么问题呢,乘法溢出,因为最高位数是10000^10000位,这样的位数用我们以前学到高精度也不行了,我们需要用到压位的方法!,AC代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n,l=1,g[1000010];

struct people{
    int l,r,cheng;
}peo[100010];

void gj1(int x)
{
    for(int i=1;i<=l;i++) g[i]*=peo[x].l ;
    for(int i=1;i<=l;i++)
    {
        g[i+1]+=(g[i]/10);
        g[i]%=10;
    }
    l++;
    while(g[l]>9)
    {
        g[l+1]+=(g[l]/10);
        g[l]%=10;
        l++;
    }
    if(g[l]==0) l--;
}
void gj2()
{
    for(int i=l;i>=1;i--)
    {
        g[i-1]+=((g[i]%peo[n].r)*10);
        g[i]/=peo[n].r;
    }
    while(g[l]==0) l--;
    if(l==0) printf("1\n");
}

int cmp(people a,people b){
    return a.cheng<b.cheng;
}

int main()
{
    cin>>n;
    for(int i=0;i<=n;i++)
    {
        scanf("%d %d",&peo[i].l,&peo[i].r);
        peo[i].cheng=peo[i].l*peo[i].r;
    }
    peo[0].cheng=peo[0].l ;
    sort(peo+1,peo+n+1,cmp);
    g[1]=peo[0].l;
    for(int i=1;i<n;i++) gj1(i);
    gj2();
    for(int i=l;i>=1;i--) printf("%d",g[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Liukairui/article/details/81255660