H - Checker FZU - 2041
Posted Jozky86
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了H - Checker FZU - 2041相关的知识,希望对你有一定的参考价值。
题意:
一个长度为n的01串,现在能将里面的1移动m次,问最长的连续0是多长
题解:
没想出来,看了其他人代码,就是对于每个0空间进行扩充,然后记录每次扩充的最大值
关键在于扩充的细节:
我们每次锁定一个连续的0的左右端点(图中的left和right)
然后看left和right分别向外找最近的0,我们可以通过下图看出,左侧长度为lena可以找到0,右侧lenb可以找到0,lena<lenb,所以我们移动左侧
每次移动也是缓慢移动,我们让i和j进行交换,然后看left-1(即k的位置)是否为0,如果是0,left就向左移动,相当于扩大区间,
为什么要先交换i和j呢?因为要扩大范围,只能先换走j,再换走k,一步一步来,不能着急,每次移动都会消耗步数
这个思路很妙
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
typedef long long LL;
const double eps = 1e-6;
const int INF = 0x3f3f3f3f;
const int MAXN = 500 + 10;
int t, len, step;
char G[MAXN], CG[MAXN];
int Calc(int left, int right) {
strcpy(CG, G);
int cnt = step;
int low = left - 1, high = right + 1;
while (cnt--)
{
if (low - 1 < 0 && high + 1 >= len) break;
for (;;)
{
if (low - 1 < 0 && high + 1 >= len) break;
int lena = INF, lenb = INF;
bool yes = false;
if (low - 1 >= 0 && CG[low - 1] == '0') {//记录两个0之间相隔1的数量
lena = left - (low - 1);
yes = true;
}
if (high + 1 < len && CG[high + 1] == '0') {
lenb = high + 1 - right;
yes = true;
}
if (!yes) {//如果low和high还没找到0,继续向外找
--low;
++high;
continue;
}
if (lena < lenb) {//相隔1最少的
swap(CG[low], CG[low - 1]);
if (CG[left - 1] == '0') {//查看left是否可以向左扩展
--left;
}
}
else {
swap(CG[high], CG[high + 1]);
if (CG[right + 1] == '0') {
++right;
}
}
low = left - 1;
high = right + 1;
break;
}
}
return right - left + 1;
}
int main() {
scanf("%d", &t);
int cas = 0;
while (t--) {
scanf("%d%d%s", &len, &step, G);
int ans = 0;
for (int i = 0; i < len;) {
if (G[i] == '0') {
int j = i;
while (j + 1 < len && G[j + 1] == '0') { ++j; }//每次找到连续0的左右端点
ans = max(ans, Calc(i, j));
i = j + 1;
}
else {
++i;
}
}
printf("Case %d: %d\\n", ++cas, ans);
}
return 0;
}
以上是关于H - Checker FZU - 2041的主要内容,如果未能解决你的问题,请参考以下文章