USACO 2024 December Contest, SilverProblem 1. Cake Game (AcWing 6118. 蛋糕游戏)Python 题解

USACO 2024 December Contest, SilverProblem 1. Cake Game (AcWing 6118. 蛋糕游戏)Python 题解

Bessie 和 Elsie 发现了一行 N N N 个蛋糕 ( 2 ≤ N ≤ 5 ⋅ 1 0 5 , N 为偶数) (2≤N≤5⋅10^5,N 为偶数) 2N5105N为偶数),大小依次为 a 1 , a 2 , … , a N ( 1 ≤ a i ≤ 1 0 9 ) a_1,a_2,…,a_N(1≤a_i≤10^9) a1,a2,,aN1ai109

两头奶牛都想吃到尽可能多的蛋糕。但是,作为非常文明的奶牛,她们决定玩一个游戏来分割蛋糕!游戏在两头奶牛之间轮流进行回合。每个回合进行以下两者之一:

Bessie 选择两个相邻的蛋糕并将它们堆叠起来,制造大小为两者大小之和的一个新蛋糕。
Elsie 选择最左边或最右边的蛋糕藏起来。
当只剩下一个蛋糕时,Bessie 吃掉它,而 Elsie 吃掉她藏起来的所有蛋糕。如果两头奶牛都采取最优策略以最大化她们吃到的蛋糕量,并且 Bessie 先进行回合,那么每头奶牛将会吃到多少蛋糕?

输入格式(从终端 / 标准输入读入):
每个测试点包含 T ( 1 ≤ T ≤ 10 ) T(1≤T≤10) T1T10个独立的测试用例。输入保证一个测试点中的所有 N N N之和不超过 1 0 6 10^6 106
每个测试用例的格式如下。
第一行包含 N N N
下一行包含 N N N个空格分隔的整数 a 1 , a 2 , … , a N a_1,a_2,…,a_N a1,a2,,aN

输出格式(输出至终端 / 标准输出):
对于每个测试用例,输出一行,包含 b 和 e,表示 Bessie 和 Elsie 在两头奶牛都采取最优策略的情况下分别吃到的蛋糕量。
输入样例:

2
4
40 30 20 10
4
10 20 30 40

输出样例:

60 40
60 40

对于第一个测试用例,在最优策略下,
Bessie 将堆叠中间两个蛋糕。现在蛋糕的大小为 [ 40 , 50 , 10 ] [40,50,10] [40,50,10]
Elsie 将吃掉最左边的蛋糕。现在剩余的蛋糕的大小为 [ 50 , 10 ] [50,10] [50,10]
Bessie 堆叠剩余的两个蛋糕。
Bessie 将吃到 30 + 20 + 10 = 60 30+20+10=60 30+20+10=60的蛋糕,而 Elsie 将吃到 40 40 40的蛋糕。

第二个测试用例是第一个测试用例反转的情况,因此答案相同。

测试点性质:
测试点 2:所有 a i a_i ai相等。
测试点 3: N ≤ 10 N≤10 N10
测试点 4-7: N ≤ 5000 N≤5000 N5000
测试点 8-11:没有额外限制。

题解

这题个人感觉挺抽象难理解的。不太好做说实话。我也是去看了闫老师的题解蓝桥杯集训·每日一题 | AcWing 6118. 蛋糕游戏。但是没太听懂,主要是听懂了A的选蛋糕策略。然后自己又理了一遍才比较明白。写一篇题解当复习笔记用了。

题目要点!

我一开始乍一眼没看懂,直接就去看了闫老师的题解。然后懵逼了。后面才后知后觉发现题目要点是什么:
表示 Bessie 和 Elsie 在两头奶牛都采取最优策略的情况下分别吃到的蛋糕量

最优策略!

这里把两头奶牛称为A和B,A奶牛是Bessie,B奶牛是Elsie。都采取最优策略。什么是最优策略。
显然B的最优策略非常好理解,就是每轮左右选最大!
那么A的最优策略呢?它的目标很好理解,就是吃最多!但是怎么选才能吃最多?

首先就是根据闫老师的方案,可以保证A必吃 n / / 2 + 1 n//2+1 n//2+1 个蛋糕。

然后我就证明了一下,如果A合并的蛋糕杯有被B吃了的,还有没有可能让A吃的蛋糕多?证明结果就是不行,A必须满满当当吃完 n / / 2 + 1 n//2+1 n//2+1个蛋糕才是最大的,但凡有一个合并的蛋糕被B吃了,最好情况也是少于某个吃满 n / / 2 + 1 n//2+1 n//2+1个蛋糕的情况。

非常好证明,假设B吃掉了一个合并蛋糕( a i , a i + 1 a_i,a_{i+1} ai,ai+1),B吃掉的是左边 0 ∼ i 0\sim i 0i(合并后 i , i + 1 → i i,i+1 \rightarrow i i,i+1i),右边则是 t ∼ n t\sim n tn,那么就一定有一种方案是 a i , a i + 1 a_i,a_{i+1} ai,ai+1没被合并,然后A吃了 a i + 1 a_{i+1} ai+1,B依然吃的是左边 0 ∼ i 0\sim i 0i,右边 t ∼ n t\sim n tn的方案。

那么显然A吃掉 a i + 1 a_{i+1} ai+1显然是要比A没吃到 a i + 1 a_{i+1} ai+1蛋糕值要大的!

那么问题来了,既然A必然可以吃掉 n / / 2 + 1 n//2+1 n//2+1个蛋糕(按照闫总的方案),那么A的最优方案是什么?这个时候就是看A、B博弈了,显然在闫老师那个方案里,A是必然被动的,B才是主动的那个。那么A的最优方案的方案只能是A所有吃完 n / / 2 + 1 n//2+1 n//2+1 个蛋糕方案中最小的那个,因为主动的B显然会一直捡场面上左右两边最大的蛋糕来吃,而A如果此时不想让自己吃的少,那么只能让自己委屈了(但凡敢合并可以被B吃的蛋糕,那么必然会有前面证明的情况出现)!

然后就可以算A吃完 n / / 2 + 1 n//2+1 n//2+1个蛋糕方案中最小的那个出来,然后就得到了B的值

代码

t = int(input())

for i in range(t):
    n = int(input())
    cakes = list(map(int, input().strip().split()))
    total = sum(cakes)
    pre = [0 for _ in range(n+1)]
    for i in range(1, n+1):
        pre[i] = pre[i-1] + cakes[i-1]
    win = float("INF")
    for i in range(n//2+1, n+1):
        win = min(win, pre[i]-pre[i-n//2-1])
    print(win, total-win)

在这里插入图片描述
有没有可能用滑动窗口做这题?显然是可以滴。(求B的最大取值嘛)

t = int(input())

for i in range(t):
    n = int(input())
    cakes = list(map(int, input().strip().split()))
    total = sum(cakes)
    newcakes = cakes+cakes
    len_win = n//2-1
    newcakes = newcakes[n-len_win:n+len_win]
    tmp, win = 0, 0
    for idx, cake in enumerate(newcakes):
        tmp += cake
        if idx < len_win-1:
            continue
        win = max(win, tmp)
        tmp -= newcakes[idx-len_win+1]
    print(total-win, win)

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值