码迷,mamicode.com
首页 > 其他好文 > 详细

P1080 国王游戏

时间:2018-10-19 00:19:59      阅读:196      评论:0      收藏:0      [点我收藏+]

标签:als   快排   如何   lin   spl   解法   init   include   大小   

暴力不会写,直接抄题解系列。。。

这道题人云亦云说是贪心。但是重点是如何证明贪心是对的。

需要给定一定的排列来使拿到最多钱的大臣拿的最少,其实就是个排序。

我们讨论两个前后关系的大臣,如何才能使答案最小。

设两位大臣一位叫\(a\),一位叫\(b\),把他们前面的人(包括国王)的左手的乘积统称为\(tot\)

\(a\)排在\(b\)前面,则\(a\)得到的钱是\(\frac{tot}{r_a}\)\(b\)得到的钱是\(\frac{tot \times l_a}{r_b}\)

而当\(b\)排在\(a\)前面,则\(b\)得到的钱是\(\frac{tot}{r_b}\)\(a\)得到的钱是\(\frac{tot \times l_b}{r_a}\)

显然,第一种情况\(b\)拿到的钱比第二种情况\(a\)拿的钱多,并且第二种情况\(b\)拿到的钱比第一种情况\(a\)拿到的钱多。

所以这两对大小关系我们根本不需要去比较。。。

现在设第二种情况更优。

那么一定会有\(\frac{tot \times l_b}{r_a} < \frac{tot \times l_a}{r_b}\),可以约掉\(tot\),再同乘以\(r_ar_b\),就可以得到

\[l_b \times r_b < l_a \times r_a\]

所以在两者之间,左手乘右手的积较小的,答案会更小。

这样的证明可以在冒泡排序中成立,那么其他排序呢?

也成立!难道冒泡成立的,快排就不成立啦?!

所以这就是这道题的解法:按照左手乘以右手的积从小到大排序,每个人算下自己拿的钱,取max即可。


然后要命的来了:这道题需要高精度!

不过也是简单的高精度。因为这道题只需要处理高精乘低精和高精除以低精这两种操作,重载运算符即可搞定。

因为我之前根本没掌握过这些高精低精互相运算的东西,所以也抄了别人的题解。。。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
const int maxn = 1005;
struct Nodes
{
    int l, r;
    bool operator < (const Nodes &rhs) const
    {
        return l * r < rhs.l * rhs.r;
    }
} s[maxn];
int n;
int L, R;
struct INT
{
    int a[10005], len;
    INT()
    {
        memset(a, 0, sizeof a);
        len = 0;
    }
    void init(int x)
    {
        if(x == 0) len = 1;
        else
        {
            while(x)
            {
                a[len++] = x % 10;
                x /= 10;
            }
        }
    }
    bool operator < (const INT &rhs) const
    {
        if(len != rhs.len) return len < rhs.len;
        for(int i = len - 1; i >= 0; i--)
        {
            if(a[i] < rhs.a[i]) return true;
            else if(a[i] > rhs.a[i]) return false;
        }
        return false;
    }
    INT operator * (const int &rhs) const
    {
        INT ret;
        for(int i = 0; i < len; i++) ret.a[i] = a[i] * rhs;
        int llen;
        for(int i = 0; i < len || ret.a[i]; i++)
        {
            if(ret.a[i] / 10)
            {
                ret.a[i + 1] += ret.a[i] / 10;
                ret.a[i] %= 10;
            }
            llen = i;
        }
        if(ret.a[llen] == 0) ret.len = llen;
        else ret.len = llen + 1;
        return ret;
    }
    INT operator / (const int &x) const
    {
        INT ret;
        ret.len = len;
        int rest = 0;
        for(int i = len - 1; i >= 0; i--)
        {
            rest = rest * 10 + a[i];
            ret.a[i] = rest / x;
            rest %= x;
        }
        while(ret.len > 1 && ret.a[ret.len - 1] == 0) ret.len--;
        return ret;
    }
    void print()
    {
        for(int i = len - 1; i >= 0; i--) printf("%d", a[i]);
        printf("\n");
    }
};
int main()
{
    /*
    while(233)
    {
        int x, y; scanf("%d%d", &x, &y);
        INT xx; xx.init(x);
        INT yy; yy.init(y);
        INT res1 = xx * y, res2 = xx / y;
        res1.print();
        res2.print();
        printf("%d\n", xx < yy);
    }
    return 0;
    */
    
    scanf("%d%d%d", &n, &L, &R);
    for(int i = 1; i <= n; i++) scanf("%d%d", &s[i].l, &s[i].r);
    std::sort(s + 1, s + n + 1);
    INT temp; temp.init(L);
    INT ans;
    for(int i = 1; i <= n; i++)
    {
        ans = std::max(ans, temp / s[i].r);
        temp = temp * s[i].l;
    }
    ans.print();
    return 0;
    
}

P1080 国王游戏

标签:als   快排   如何   lin   spl   解法   init   include   大小   

原文地址:https://www.cnblogs.com/Garen-Wang/p/9813320.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!