题意:
给了你一个01字符串,你可以删除字符串的头部若干元素,尾部若干元素(亦可以不删除),现在让你求一个代价,代价是剩余字符串中的0的个数和删除了的字符串中的1的个数的最大值。
思路:
根据题意是让你求最大的最小值,那么这个题就是一个二分,二分+双指针。
题目中让我们求成本,那么我们直接对成本进行二分即可,我们需要用两个数组来装0的前缀和和1的前缀和,现在来想一下二分的check函数:
我们二分的是成本,成本要么是删除了的中的1,或者是剩下的0,下面想一下双指针怎么用,这里我们用的是快慢指针,l = 0, r = 1。来看代码
/*
最大值最小
*/
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int sum1[N], sum0[N];
string s;
int len;
bool check(int ans)
{
for (int l = 0, r = 1; r <= len; r ++)
{
/*
首先双指针内的0的数目不能超过ans,因为我们取的最大值就是ans,然后我们要区间的长度尽量的长,这个答案的最大值才可能尽量的小。(说明一下,字符串给定了,说明每个区间内的01的数目是固定了的)
然后我们在来考虑区间以外的1的数目,1的数目也不能超过ans,如果这段区间以外的1的数目<=ans,说明我们的区间找大了,区间找大了说明二分的答案大了,则return true。
*/
while (l < r && sum0[r] - sum0[l] > ans) l ++;
if (sum1[l] + sum1[len] - sum1[r] <= ans) return true;
}
return false;
}
void solve()
{
cin >> s;
len = s.length();
s = " " + s;
for (int i = 1; i <= len; i ++)
{
sum0[i] = sum0[i - 1] + ((s[i] - '0') ^ 1);
sum1[i] = sum1[i - 1]+ (s[i] - '0');
}
int l = 0, r = len;
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
cout << l << endl;
}
int main()
{
std::ios::sync_with_stdio(false);
int t; cin >> t;
while (t --) solve();
return 0;
}