当前位置: 首页 > news >正文

题解:luogu_P13309 演剧

非常好玩的一道博弈论的题目,结论与证明都非常巧妙,在翻月赛题目时看到的。蒟蒻希望能尽可能地讲清楚思考过程和结论的证明,如有问题请指出。

原题链接。

题目分析

为方便叙述,我们称分割的人为先手,另外一个人为后手。

二分答案 \(x\),将原序列中大于等于 \(x\) 的位置变为 \(1\),反之变为 \(0\)。那么问题就转化为雪能否取到 \(1\)

我们记新序列中 \(1\) 的个数为 \(cnt_1\)\(0\) 的个数为 \(cnt_0\)。我们猜测,当 \(cnt_1 > cnt_0\) 时,雪一定能赢;当 \(cnt_1 < cnt_0\) 时,K 一定能赢。

证明:问题的关键就是证明某一方的优势能否一直保持

  1. \(cnt_1 > cnt_0\) 时,被 K 分割后回有两种情况:两段都是 \(cnt_1' > cnt_0'\);一段是 \(cnt_1' > cnt_0'\),一段是 \(cnt_1' = cnt_0'\)。我们只需考虑第二种情况。

    \(cnt_1' = cnt_0'\) 的这一段非常特别,我们只考虑它在右边的情况。记 \(pre_{i,1}, pre_{i,0}\) 分别表示 \(1,0\) 个数的前缀和,这个序列只有最后一个位置满足 \(pre_{i, 1} = pre_{i, 0}\),否则我们可以将前面这些 \(pre_{i, 1} = pre_{i, 0}\) 的小段合并到做左边的序列,这样也符合我们的设定。

    这么说可能有点抽象,下面举个例子。比如 1 1 0 1 0 1 0 这个序列,如果我们选择从 \(3\) 位置分开,即分成 1 1 01 0 1 0。但是我们完全可以把第一段 1 0 合并到左边,即分成 1 1 0 1 01 0

    如果这个序列只有最后一个位置满足 \(pre_{i, 1} = pre_{i, 0}\),那么在任何一个位置分,都会分成 \(cnt_1' > cnt_0'\)\(cnt_1' < cnt_0'\) 的两段,雪完全可以选择 \(cnt_1' > cnt_0'\) 的这一段,那么雪的优势便能一直保持。

  2. \(cnt_1 < cnt_0\) 时,证明与 \(cnt_1 > cnt_0\) 的方法一样,不多赘述。

我们再来想想 \(cnt_1 = cnt_0\) 时的情况,咱先来手模几个。1 0 1 0 雪能赢,1 0 1 0 1 0 K能赢,1 0 1 0 1 0 1 0 雪又能赢。我们发现每个人的输赢好像是交替出现的。

我们把满足 \(pre_{i, 1} = pre_{i, 0}\)\(i\) 称为一个“前缀点”。观察上面的例子,猜测如果有奇数个前缀点,那么 K (后手)能赢;如果有偶数个前缀点,雪(先手)能赢。

首先要发现的一点是,雪和 K 都不可能在前缀点以外的位置分割,与上文一样,这样一定会分成 \(cnt_1' > cnt_0'\)\(cnt_1' < cnt_0'\) 的两段,那么下一个人就可以根据自己的需求选择一段,从而获取胜利。

我们可以用归纳证明:设前缀点个数为 \(m\)

  1. \(m\) 为奇数:当 \(k = 1\) 时,根据情况1的结论,后手能赢。假设当 \(k = m\) 时成立,当 \(k = m + 2\) 时,前两轮先手都在倒数第二个前缀点分开 (这一定不会使答案变坏,可以仔细想想),那么剩下的就是 \(k = m\) 的情况,注意此时的先手没变,情况完全相同。

  2. \(m\) 为偶数:同样地,选择倒数第二个前缀点分开,情况变成了 \(n\) 为奇数时的情形,不过现在的后手是刚开始的先手,那么先手一定能赢。

所以我们只需要找到最大的满足 \(cnt_1 > cnt_0\) 的数即可,这在原序列中就是中位数。不过注意,当 \(n\) 为偶数时,还要判断 \(\frac{n}{2} + 1\) 位置上的数是否可行。

如果排序求中位数,时间复杂度为 \(O(n \log n)\),如果是线性求,则可做到 \(O(n)\)

Code

#include <bits/stdc++.h>
using namespace std;constexpr int N = 1e5 + 9;
int n;
int a[N], b[N], pre[2];void solve(){cin >> n;for(int i = 1; i <= n; i++) cin >> a[i], b[i] = a[i];sort(b + 1, b + 1 + n);if(n & 1){cout << b[(n + 1) / 2] << '\n';//中位数return;}int x = b[n / 2 + 1];//偶数要特判int res = 0;for(int i = 1; i <= n; i++){int c = (a[i] >= x);pre[c]++;if(pre[0] == pre[1]) res++;}if(res & 1) cout << b[n / 2] << '\n';else cout << x << '\n';pre[1] = pre[0] = 0;
}int main(){int T;cin >> T;while(T--) solve();return 0;
}
http://www.sczhlp.com/news/37750/

相关文章:

  • 167 两数之和二
  • 15 三数之和
  • Idea 2025.2.2 maven乱码解决
  • 浪起科技做的网站怎么样如何进行线上推广
  • 传奇私服网站花生壳怎么做免费建站工具
  • 广州公司建设网站最近发生的重大新闻
  • 安阳网站建设emaimaseo网站推广企业
  • 做网站设计需要学会哪些企业培训课程
  • 2133D-Chicken Jockey
  • 读《活着》有感:原来人生还能有这样的活法
  • 网站做支付端口的费用电子商务推广
  • 怎么做电视台网站2023免费网站推广大全
  • 工信和信息化部网站互联网舆情信息
  • 17网一起做网站广州网站seo优化软件
  • 安阳网站建设公司网络域名
  • 提供网站建设公西安发布最新通知
  • 洛阳青峰做网站广告推广怎么做
  • 浦东网站开发培训班2022年新闻摘抄十条
  • 涡阳网站建设哪家好最近新闻报道
  • 【VPX630】基于KU115 FPGA+C6678 DSP的6U VPX通用超宽带实时信号处理平台
  • 芯片封装
  • 程序员必备工具-Git和TortoiseGit的安装和使用
  • k8s笔记
  • 英文网站建设之后怎么推公司域名查询官网
  • 网站子页面设计今日热点事件
  • 宿州网站建设多少钱app拉新项目一手渠道商
  • 网站的背景图怎么做怎么做外链
  • 网站建设脱颖而出手机优化大师官网
  • 网站建设的作用和用途友情链接属于免费推广吗
  • 制造网站开发西安百度推广优化公司