I.小沙的金银阁

I.小沙的金银阁

题目描述

小沙开设了金银阁娱乐场所,前去邀请小雅来游玩。

金银阁的规则是:每轮游戏开始之前需要压下一定的灵石(玩家指定,但不得超过自身所带的灵石上限),如果失败,则输掉该轮压的所有灵石,如果获胜则获得该轮所压灵石数以及本金。

小雅带来了 m 块灵石,这时有一位预言家告诉小雅,你接下来参加的 n场比赛,仅有一场能够押对赚灵石,其它的 n−1 场均会输掉灵石。现需要小雅设计她的方案,当她获胜之后,她就会卷灵石跑路(因为显然接下来每局是必输的)。小雅想请你帮她设计最优的赚灵石方案。

你需要保证,小雅每场所压灵石数均为正整数

在能必定不会亏灵石的条件下(你可以玩完n轮下来,一分钱没赚),对于任意的另一个方案,在第 X 轮获胜的时候,前 X−1 轮,每轮结束之后剩余灵石相同,第 X 轮获胜时总灵石越多,则该方案优于其它方案。

例如:

比赛轮数为 3 ,灵石数为 1 。
方案1为: 2 , 3 , 6 。
方案2为: 2 , 2 , 7 。
则方案 1 更优,因为方案 1 第 2 轮获胜之后,有 12个灵石,方案 2 ,第二轮获胜只拥有 11 个灵石。

输入描述:

第一行输入两个整数,n,m,其中 n 代表比赛的轮数,m 代表小雅带来的灵石数,\(1 \le n \le 10^5\),\(1 \le m \le 10^{15}\)

输出描述:

输出 n 个正整数,并保证他们的和不超过 m ,如果没有方案能够赚取灵石,输出一个 -1 。

输入

3 11

输出

2 3 6

说明

本方案中:
如果第1轮获胜,那么可以赚取2块灵石,已有11个灵石,总灵石数为13。
如果第2轮获胜,那么可以赚取3块灵石,已有9个灵石,总灵石数为12。
如果第3轮获胜,那么可以赚取6块灵石,已有6个灵石,总灵石数为12。

思路点拨1:

借鉴思路 「CCSU_梅子酒」

  • 我们首先要构造出一种保证不会亏损的方案,我们假设第一轮下注x枚灵石,如果第一轮就赢显然不亏,如果输了那么我们就要考虑第二轮赢把第一轮的灵石赢回来的情况,就也要下注 x 枚灵石,同理第三轮我们要考虑第三轮赢回前两轮输掉的灵石,下注 \(2x\),以此类推每轮都要下注前一轮两倍的灵石数,第 n 轮就需要下注 \(x * 2^{n-2} \) ,n 轮总共要下注 \(x * 2^{n-1} \) 枚灵石,等比数列前n-1项和,由于前n-1项和为\(x*2^0,x*2^1,x*2^2,\cdots,x*2^{n-2}\)相加得到,所以根据等比数列前n项和公式(n为项数):\(S_n=\dfrac{a_1(1-q^n)}{1-q}\),得到前n-1项和为\(x*(2^{n-1}-1)\)。但是由于原序列为\(x*1,x*1,x*2,x*4,x*8,\cdots,x*2^{n-2}\),所以最终和为\(x*2^{n-1}\)。所以要满足下注的所有灵石和不能超过 m,所以最小的合法方案就是当 x = 1的时候,每次都只下注最低标准的灵石,如果 \(m < 2^{n-1} \) 则输出 −1,无合法方案。最小方案的构造方法是,每次只下注最小的满足金额,第一次下注 1,之后的每一轮都按照该轮会赢,且我们只赢回本金的方法下注。
  • 当能保证不亏损时再去考虑如何更优,注意题目中所说的 前 X−1 轮,每轮结束之后剩余灵石相同,第 X 轮获胜时总灵石越多,则该方案优于其它方案。 我们从最小的方案开始想起,如何能更优的构造,假设前 n − 1 轮下注灵石相同,在最后一轮我们不下注 \(2 ^ {n-2}\), 而是下注更多,这样在第 n轮我们获胜的这一种情况下就会更优,其他轮获胜的情况相同。 同理向前推,第 n − 1 轮如果也下注更多在保证第 n 轮能不亏本的情况下会更优。所以结论是在保证不亏的基础上,下注越多越好。前面赌的灵石越大越好,所以我们直接从后面开始做起,考虑最后面一场只要保本就好,取一半向上取整的数目的灵石,然后不断重复操作即可。

思路点拨2:

  • jiangly赛时代码思路:
  • 数据范围可以优化一下,对于\(2^{50}\)已经超过了18位数字,所以如果n>50了,那么对于m<\(10^{15}\)来说,应该永远都满足\(m < 2^{n-1}\)
  • 对于从后向前向上取整,保证不亏这个条件,可以分析得到如果后面是向上取整的得到的,那么前面一定是向下取整的得到的,那么我们完全可以正过来算,可以从前向后算,。
  • 不懂没事,我也对原理也不是很懂,但是可以通过实例解释一番。
  • e.g.题目所给k = 3,n = 11。
    • 先从后向前考虑,对11进行除以2,得到向上取整结果6和向下取整结果5,然后对5进行除以2,得到向上取整结果3和向下取整结果2,所以最后答案为2,3,6。
    • 然后从前向后考虑,对于第一次应该除以的数是2的2次方,也就是4,得到向下取整结果为2和向上取整结果为3,而第二次应该除以的数就是2的一次方,也就是2,得到向上取整结果6和向下取整结果5,对于5来说正好是前面两个数的和。所以这两种考虑方式是等价的,

提交代码

简单从后向前思路代码

#include <bits/stdc++.h>

using i64 = long long;


int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    i64 n,m;
    std::cin>>n>>m;
    i64 s[100005];
    s[n]=m;
    for(int i=n-1;i>=1;i--)
    {
        s[i]=s[i+1]/2;
        s[i+1]=s[i+1]-s[i];
        if(s[i]==0)
        {
            std::cout<<-1;
            return 0;
        }
    }
    for(int i=1;i<=n;i++){
        std::cout<<s[i]<<" \n"[i==n];
    }
    return 0;
}

jiangly大佬赛时从前向后计算代码:

#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int n;
    i64 m;
    std::cin >> n >> m;
    
    if (n > 50 || (1LL << (n - 1)) > m) {
        std::cout << -1 << "\n";
        return 0;
    } 
    
    i64 sum = 0;
    for (int i = 0; i < n; i++) {
        i64 x = (m >> (n - i - 1)) - sum;
        std::cout << x << " \n"[i == n - 1];
        sum += x;
    }
    
    return 0;
}

posted @ 2023-02-24 22:47  哲远甄骏  阅读(54)  评论(0)    收藏  举报