社交距离 I
社交距离 I
一种新型疾病,COWVID-19,开始在全世界的奶牛之间传播。
Farmer John 正在采取尽可能多的预防措施来防止他的牛群被感染。
Farmer John 的牛棚是一个狭长的建筑物,有一排共 个牛栏。
有些牛栏里目前有奶牛,有些目前空着。
得知“社交距离”的重要性,Farmer John 希望使得 尽可能大,其中 为最近的两个有奶牛的牛栏的距离。
例如,如果牛栏 和 是最近的有奶牛的牛栏,那么 。
最近两头奶牛新来到 Farmer John 的牛群,他需要决定将她们分配到哪两个之前空着的牛栏。
请求出他如何放置这两头新来的奶牛,使得 仍然尽可能大。
Farmer John 不能移动任何已有的奶牛;他只想要给新来的奶牛分配牛栏。
输入格式
输入的第一行包含 。
下一行包含一个长为 的字符串,由 和 组成,描述牛棚里的牛栏。
表示空着的牛栏, 表示有奶牛的牛栏。
字符串中包含至少两个 ,所以有足够的空间安置两头新来的奶牛。
输出格式
输出 Farmer John 以最优方案在加入两头新来的奶牛后可以达到的最大 值(最近的有奶牛的牛栏之间的距离)。
数据范围
输入样例:
14 10001001000010
输出样例:
2
样例解释
在这个例子中,Farmer John 可以以这样的方式加入奶牛,使得牛栏分配变为 ,其中 表示新来的奶牛。
此时 。
不可能在加入奶牛之后取到更大的 值。
解题思路
分情况来讨论,一共有两种情况。
- 两头牛在同一个区间。
- 两头牛在不同的区间。
我们把首尾区间和中间的区间分开来看。
对于首尾区间,如果要把两头牛都放在首区间中,很明显,当把一头牛放在左端点时,另一头牛距离左右两头牛的距离才会尽可能的大。那么另一头牛应该放在什么地方?假设这头牛距离左端点的牛的距离为,距离的距离为,那么应该有。当和越接近时,和中的最小值才会越大,我们让。如果得到的距离是整数的话,那么和取相等。如果不是整数,那么下取整,比如,那么会得到一个是,另一个是,我们应该取。
尾区间同理,最小的距离应该是,是序列中最后一头牛的下标,在上面的序列中。
对于中间的区间,当放入两头牛后会有三段距离,一段是一头牛与区间左边的牛的距离,一段是两头牛之间的距离,一段是另一头牛与区间右边的牛的距离。同理会有。要使这三个数的最小值最大,应该有让,假设的值最小,那么有。
现在我们要看放在哪一个区间更好,也就是可以取到最大的最小值。
先看把牛放入中间区间的情况,假设在没放牛之前的初始情况,任意两个牛之间的距离为,其中,以此类推。假设我们把牛放入第个区间,得到的最小距离是,那么最后所有牛间的最小值就应该是,由因为,因此我们可以把放入进行比较,这并不会影响最终答案,因此就有。可以发现,这对于任何中间的区间都成立,只需要把改成对应放入的区间即可。而对于首尾区间的情况,同样只需要把换成首尾区间的结果。因此为了使得最小的距离最大,应该取所有的的最大值。假设一开始已存在的牛之间的最小距离为,因此对于把牛都放入同一个区间的情况,能够取到的最大距离就为。
然后是把牛放入不同区间的情况。如果放在首尾区间,那么应该放在左端点或右端点上,距离分别为和。如果是放在中间的中,那么最小距离的最大值为。我们在每一个区间中都放一头牛得到上述的距离,最后在这些距离中找到最大值和次大值,那么我们应该把这两头牛分别放入这两个对应区间中,最小距离可以取到最大值。假设最大值和次大值分别为和,和第一种情况一样,,因此能够取到的最大距离就为,即。
最后的答案应该就是求出这两种情况的结果中,取最小值。
如果不存在首区间或尾区间,根据上面的公式,会有及,对于两种放法,我们都是取所有放入后的距离的最大值,而并不会影响取最大值,因此也是成立的。
AC代码如下:
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 5 const int N = 1e5 + 10; 6 7 char str[N]; 8 int pos[N]; 9 10 int main() { 11 int n; 12 scanf("%d %s", &n, str + 1); 13 14 int cnt = 0; 15 for (int i = 1; i <= n; i++) { 16 if (str[i] == '1') pos[++cnt] = i; // 记录初始时有牛的位置 17 } 18 19 if (cnt == 0) { // 如果一头牛的没有,那么两头牛应该放在左右端点 20 printf("%d", n - 1); 21 return 0; 22 } 23 24 int minx = N; // 初始时,两头牛之间的最小距离 25 for (int i = 1; i < cnt; i++) { 26 minx = min(minx, pos[i + 1] - pos[i]); 27 } 28 29 // 把两头牛放入同一个区间 30 int y = max(pos[1] - 1 >> 1, n - pos[cnt] >> 1); // 先对首尾区间这种特殊情况进行判断 31 for (int i = 1; i < cnt; i++) { 32 y = max(y, (pos[i + 1] - pos[i]) / 3); // 处理中间区间的情况 33 } 34 35 // 把两头牛放入不同的区间 36 int y1 = pos[1] - 1, y2 = n - pos[cnt]; // 先对首尾区间进行特判 37 if (y1 < y2) swap(y1, y2); // y1是最大值,y2是次大值 38 for (int i = 1; i < cnt; i++) { 39 int t = pos[i + 1] - pos[i] >> 1; // 处理中间区间的情况 40 41 // 维护最大值和次大值 42 if (t >= y1) y2 = y1, y1 = t; 43 else if (t > y2) y2 = t; 44 } 45 46 printf("%d", min(minx, max(y, y2))); 47 48 return 0; 49 }
这题还可以用二分。一开始的搜索的左右端点值为。
对于check函数,假设要判断的最小距离的最大值能否为,先从头到尾扫描一遍序列,然后如果某个位置为,那么把牛放入这个位置,然后判断与前一头牛和后一头牛的距离,应该要满足,其中表示前一头牛的位置,为在这个位置的后一头牛的位置,可以预处理出来。只有满足这个条件,才可以把牛放入,并更新pre为。最后判断能否放入两头牛。
AC代码如下:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 const int N = 1e5 + 10, INF = 0x3f3f3f3f; 7 8 int n; 9 char str[N]; 10 int a[N], ne[N]; 11 12 bool check(int x) { 13 int cnt = 0; 14 for (int i = 1, pre = -INF; i <= n; i++) { // 一开始pre设为负无穷,意味着在最左边有一头牛 15 if (a[i] == 0 && i - pre >= x && ne[i] - i >= x) { 16 if (++cnt >= 2) return true; 17 pre = i; 18 } 19 else if (a[i] == 1) { 20 pre = i; 21 } 22 } 23 24 return false; 25 } 26 27 int main() { 28 scanf("%d %s", &n, str + 1); 29 30 int left = 1, right = N; 31 for (int i = 1, pre = -INF; i <= n; i++) { 32 a[i] = str[i] - '0'; 33 if (a[i] == 1) { 34 right = min(right, i - pre); 35 pre = i; 36 } 37 } 38 39 // 预处理出来每头牛的下一头牛的位置,在正无穷处设一头牛 40 memset(ne, 0x3f, sizeof(ne)); 41 for (int i = n; i; i--) { 42 if (a[i] == 0) { 43 if (a[i + 1] == 1) ne[i] = i + 1; 44 else ne[i] = ne[i + 1]; 45 } 46 } 47 48 while (left < right) { 49 int mid = left + right + 1 >> 1; 50 if (check(mid)) left = mid; 51 else right = mid - 1; 52 } 53 54 printf("%d", left); 55 56 return 0; 57 }
参考资料
AcWing 1659. 社交距离 I(春季每日一题2022):https://www.acwing.com/video/3747/
AcWing 1659. 社交距离 I 二分:https://www.acwing.com/solution/content/103535/
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/16049180.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效