带数学推导的贪心(高精度乘除法应用)

原题https://www.luogu.org/problemnew/show/P1080
题解
这个国王太会玩了!!
【题意分析】
首先,由于一个大臣所获得的金币数只取决于他右手的金币数,所以前面的大臣顺序并不影响后面大臣的金币数,但会影响自己手中的金币数。然后便想到了贪心。但发现这样子并不能得出最优解。然后经过一番推导,便可以得知一个大臣的左右手乘积越大,就越要放到队伍后面。

然后就开始了玄妙的数学证明时间!!

前方高能!!!前方高能

【证明】
…(设这一段乘积为X1) …(设这一段乘积为Y2)
L1 R1
…(设这一段乘积为X2) …(设这一段乘积为Y2)
L2 R2
由上面这张表格可以知道这样的情况时:
第一个人所得的金币数为X1/R1;

第二个人所得的金币数为X1×L1×X2/R2;

所以最小值为 max(X1/R1, X1×L1×X2/R2);

然后交换两个人的位置

…(这一段乘积为X1) …(这一段乘积为Y2)
L2 R2
…(这一段乘积为X2) …(这一段乘积为Y2)
L1 R1
由上面这张表格可以知道交换后的情况时:
第一个人所得的金币数为X1×L2×X2/R1;

第二个人所得的金币数为X1/R2;

所以此时最小值为max(X1×L2×X2/R1, X1/R2);

综合上面两种情况:
如果变换之前的情况要优于变换之后的情况,那么

max(X1/R1, X1×L1×X2/R2) < max(X1×L2×X2/R1, X1/R2);

而X1/R1 < X1×L2×X2/R1 恒成立;

X1×L1×X2/R2 > X1/R2;

所以上述条件成立时

必须有X1×L1×X2/R2 < X1×L2×X2/R1 恒成立;所以化简可得 L1×R1 < L2×R2恒成立。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
int n, lens = 1, lenm = 1, lena = 1;//重要的初始化 
int sum[10010] = {0, 1}, maxn[10010] = {0, 1}, ans[10010];//重要的初始化 
//ans是高精度除法的存储数组,sum是高精度乘法的存储数组 
struct tmp
{
    long long l, r;//排序写在结构体里更快 
    bool operator < (const tmp x) const //这一行是重载符的格式 
    {
            return l * r < x.l * x.r;
    }
}coin[1001];
void muti(long long x)//高精度乘法 求累积 
{
    int tmp = 0;
    for(int i = 1; i <= lens; i++) sum[i] *= x;
    for(int i = 1; i <= lens; i++)
    {
        tmp += sum[i];sum[i] = tmp %10;tmp /= 10;
    }//进位过程 
    while(tmp != 0)
    {
        lens++;sum[lens] = tmp % 10;tmp /= 10;
    }//增加位数 
}
void cut(long long x)//高精度除法求每个大臣的奖赏 
{
    memset(ans, 0, sizeof(ans));//初始化 
    lena = lens;
    int tmp = 0;
    for(int i = lena; i >= 1; i--)
    {
        tmp *= 10;tmp += sum[i];
        if(tmp >= x)
        {
            ans[i] = tmp / x;    tmp %= x;
        }
    }
    while(ans[lena] == 0)//去掉多余的0 
    {
        if(lena == 1)    break;//保留0 
        lena--;
    }
}
void max()
{
    if(lena > lenm)
    {
        for(int i = 1; i <= lena; i++)    maxn[i] = ans[i];
        lenm = lena;//maxn数组存储最大奖赏,lenm是其位数 
    }
    else if(lena == lenm)
    {
        for(int i = lena; i >= 1; i--)
            if(maxn[i] < ans[i])
            {
                for(int j = 1; j <= lena; j++)    maxn[j] = ans[j];
                lenm = lena;
                break;
            }
    }
}
int main()
{
//  freopen("game.in", "r", stdin);freopen("game.out", "w", stdout);
    cin >> n;
    cin >> coin[0].l >> coin[0].r;//国王 
    for(int i = 1; i <= n; i++) scanf("%d %d", &coin[i].l, & coin[i].r);
    sort(coin + 1, coin + n + 1);
    for(int i = 1; i <= n; i++)
    {
        muti(coin[i - 1].l);//求累积 
        cut(coin[i].r);// 求奖赏 
        max();//依次比较最新奖赏值与历史最大奖赏值 
    }
    for(int i = lenm; i >= 1; i--) cout << maxn[i];//高精度要求倒着输出 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值