NOIP2012国王游戏

题目来源:https://www.luogu.org/problem/show?pid=1080


用贪心可以解决。


将所有人按左右手的乘积排序,这样一定可以保证结果最优。


现给出证明:


首先,任意相邻两人的顺序对于排在他们前面和后面的人没有影响。(显然)


两人左右手上的数字分别为l[1],r[1],l[2],r[2],令l[1]*r[1]<l[2]*r[2],排在他们前面的所有人左手上的乘积为sum。


若1在2前面,那么两人分得的金币分别为sum/r[1],sum*l[1]/r[2]。


若2在1前面,两人分得的金币分别为sum/r[2],sum*l[2]/r[1]。


现比较max(sum/r[1],sum*l[1]/r[2])和max(sum/r[2],sum*l[2]/r[1])的大小:


因为l[1]*r[1]<l[2]*r[2],故max(sum/r[2],sum*l[2]/r[1])=sum*l[2]/r[1]。


而sum*l[2]/r[1]>sum/r[1]显然成立且sum*l[2]/r[1]>sum*l[1]/r[2]也成立(因为l[1]*r[1]<l[2]*r[2])。


故max(sum/r[1],sum*l[1]/r[2])<max(sum/r[2],sum*l[2]/r[1])。


故1在2前面两人分得的金币的最大值最小。


以此类推,左右手乘积较大的放在后面结果会更优。证毕。


由于此题数据较大,需要用到高精度乘法和除法。


代码:


#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <sstream>
#include <cstdio>
#include <string>
#include <vector>
#include <cmath>
#include <ctime>
#include <stack>
#include <queue>
#include <set>
#include <map>
using namespace std;
struct node{long long l,r;}c[100010];
long long a[100010],b[100010];
int n;
bool cmp(node a,node b){return a.r*a.l<b.r*b.l;}
bool comp(string s1,string s2)
{
    if(s1.size()!=s2.size())return s1.size()>s2.size();
    else
    {
        for(int i=0;i<s1.size();i++)
        {
            if(s1[i]!=s2[i])return s1[i]>s2[i];
        }
    }
    return 0;
}
string milt(string s,long long t)
{
    long long ans[10001]={0};
    long long u[10001]={0};
    for(int i=0;i<s.size();i++)u[s.size()-i]=s[i]-'0';
    for(int i=1;i<s.size()+16;i++)
    {
        ans[i]+=u[i]*t;
        if(ans[i]>=10)ans[i+1]=ans[i]/10;
        ans[i]%=10;
    }
    string e;
    int v=s.size()+16;
    while(v>1&&ans[v]==0)v--;
    for(int i=v;i>=1;i--)e+=(ans[i]+'0');
    return e;
}
string chu(string s,long long t)
{
    string e;
    long long g=0,p=0;
    while(g<t&&p<s.size())
    {
        g=g*10+s[p]-'0';
        p++;
    }
    e+=(g/t+'0');g%=t;
    for(int i=p;i<s.size();i++)
    {
        g=g*10+s[i]-'0';
        e+=(g/t+'0');g%=t;
    }
    if(e.size()==0)e='0';
    return e;
}
int main()
{
    cin>>n;
    for(int i=0;i<=n;i++)
    {
        cin>>a[i]>>b[i];
        c[i].l=a[i];
        c[i].r=b[i];
    }
    sort(c+1,c+n+1,cmp);
    string sum="1";
    string tot="0";
    for(int i=0;i<=n;i++)
    {
        string u=chu(sum,c[i].r);
        if(comp(u,tot))tot=u;
        sum=milt(sum,c[i].l);
    }
    cout<<tot;
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值