CF388C Fox and Card Game 题解
题目链接
题意概述
有 \(n\) 堆牌,每堆牌中有 \(s_i\) 张牌,每张牌上有一个数字 \(c_i\) 。
\(( 1 \leq n \leq 100 , 1 \leq s_i \leq 100 , 1 \leq c_i \leq 1000 )\)
现有 A 先手,B 后手轮流从牌堆中抽牌。A 只能从牌堆顶抽起,B 只能从牌堆底抽起。
A B 两人均贪婪,即期望所抽牌上的数字之和最大,且均做完全理性决策,求两人各自所抽取的牌上的数字之和。
思路
根据抽牌的规则,一堆牌一定能被通过以下的方式抽取结束:
本堆牌的前 \(\lfloor \frac{n}{2} \rfloor\) 张牌被 A 抽取,后 \(\lfloor \frac{n}{2} \rfloor\) 张牌被 B 抽取。
如果有一张牌剩余,则被开始抽取本堆牌时的先手方抽取。
因为两者均贪婪,所以可能有一者试图用自己一侧的一张牌去“换取”对方一侧的一张数字更大的牌。
我们举出例子:
有两堆牌,分别为 \(\{ 5,6,1,5\}\) 与 \(\{ 5,2,6,5\}\)。
此时 B 可能会试图放弃第一堆中的 \(1\) 以换取第二堆中的 \(2\) 。
但因为 A 同样贪婪,所以 A 绝不会让 B 得手。
因为 A 与 B 轮流抽牌,起初后手方可以一直跟先手方对称抽牌。
假如后手方不跟着先手方对称抽牌了,先手方就可以反过来跟着后手方对称抽牌,使得后手方总是没有机会换走先手方一侧的优势牌。
所以在 B 抽走第二堆的 \(6\) 时,A 就会立刻把 \(2\) 抽走,让 B 无法得逞。
那反过来,如果后手方一侧拿到了优势牌,只要它一直与先手方对称出牌,先手方也是永远换不走他的优势牌的。
综上,换牌有盈有亏,而贪婪的双方总是会保护自己不受亏损,所以换牌是不可能实现的。
但我们还没考虑每堆牌剩下的单张牌。
其实我们不难发现,当一堆牌的牌数为偶数时,交换先后手没有什么区别。
但是当一堆牌为奇数时,剩下的一张牌会被先手方抽取,并且使它在新的一个牌堆里变为后手方。
因为没有规定必须抽完一个牌堆才能开下一个牌堆,所以这时每个奇数牌数的牌堆,都可以把它的中间这张牌先抽出来,左 A 右 B,最后再来考虑怎么取这些中间牌。
因为每抽取一张中间牌,先后手就变一次,并且 A 和 B 都贪婪,所以 A 和 B 会在这些中间牌中轮流抽走最大的那张。
Code
#include <queue>
#include <cstdio>
using namespace std;
const int MAXN=3e5+10;
int T,n,a[MAXN],ansa,ansb;
priority_queue<int> q;
inline int read()
{
int x=0;char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x;
}
int main()
{
T=read();
while (T--)
{
n=read();
for (int i=1;i<=(n>>1);i++) ansa+=read();
if (n&1) q.push(read());
for (int i=1;i<=(n>>1);i++) ansb+=read();
}
while (!q.empty())
{
ansa+=q.top();
q.pop();
if (!q.empty())
{
ansb+=q.top();
q.pop();
}
}
printf("%d %d",ansa,ansb);
return 0;
}