洛谷P2988 - Test Taking

 OI / 洛谷
被浏览

作为一道英文题,我们先解释一下题意:

给你一个长度为 nn 的 01 串,其中可能至少有 tit_{i} 个 1,问最后你给出一个 01 串可能和其匹配的最大长度。

接下来我们进入正题。

第一眼看见觉得是水题,对于每个 tit_{i} 枚举应该全 0 还是全 1,但是这显然可以找出反例来。

那么我们应该怎么贪心呢?

首先,我们先提出一个引理:

对于两个长度为 nn 的 01 串,AAaa 个 1,BBbb 个 1,任一排列中相同位置元素相同的数量至少为 maxa+bn,nab\max\\{a+b-n,n-a-b\\}

接下来我们证明一下。

1、a+b>na+b>n,即 AABB 匹配 1。

我们为了让相同元素尽可能少,考虑把 AA 中的 1 全移到前端,BB 中的 1 全移到后端,变成线段覆盖问题,重合部分为 a+bna+b-n

2、a+b<na+b<n,即 AABB 匹配 0.

同理,我们考虑把 AA 中的 0 全移到前端,BB 中的 0 全移到后端,用同样的方法得出该情况下结果为 nabn-a-b

3、a+b=na+b=n,显然答案为 0。

说完了引理,我们再接着讲题。

我们先将 tt 从小到大排序,设当前要匹配的 01 串为 SS,其中有 xx 个 1。

对于每对 ti1,tit_{i-1},t_{i},我们肯定是拿 SSti1t_{i-1} 去匹配 0,和 tit_{i} 去匹配 1。

由引理得 Ans=maxnti1x,ti+xnAns=\max\\{n-t_{i-1}-x,t_{i}+x-n\\}

nti1xti+xnn-t_{i-1}-x \geq t_{i}+x-n 时,

Ans(titi1)/2Ans \geq (t_{i}-t_{i-1})/2

同理当 nti1xti+xnn-t_{i-1}-x \geq t_{i}+x-n 时,

Ans(titi1)/2Ans \geq (t_{i}-t_{i-1})/2

综上所述,必有 Ans(titi1)/2Ans \geq (t_{i}-t_{i-1})/2

然后特判一下 t1t_{1}tmt_{m},全选 0 或全选 1 的情况。

于是我们就可以愉快地切题了。

以下为代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
#define gc c=getchar()
int read() {
int x = 0, f = 1; char gc;
for (; !isdigit(c); gc)if (c == '-')f = -1;
for (; isdigit(c); gc)x = x * 10 + c - '0';
return x * f;
}
#undef gc
int a[10005];
int main() {
int n = read(), m = read();
for (int i = 1; i <= m; i++)a[i] = read();
sort(a + 1, a + m + 1);
int ans = max(a[1], n - a[m]);
for (int i = 1; i <= m; i++)ans = max(ans, (a[i + 1] - a[i]) / 2);
printf("%d", ans);
}