原题链接:
题目描述:
A binary string is a string consisting only of the characters 0 and 1. You are given a binary string s1s2…sns1s2…sn. It is necessary to make this string non-decreasing in the least number of operations. In other words, each character should be not less than the previous. In one operation, you can do the following:
- Select an arbitrary index 1≤i≤n1≤i≤n in the string;
- For all j≥ij≥i, change the value in the jj-th position to the opposite, that is, if sj=1sj=1, then make sj=0sj=0, and vice versa.
What is the minimum number of operations needed to make the string non-decreasing?
Input
Each test consists of multiple test cases. The first line contains an integer tt (1≤t≤1041≤t≤104) — the number of test cases. The description of test cases follows.
The first line of each test cases a single integer nn (1≤n≤1051≤n≤105) — the length of the string.
The second line of each test case contains a binary string ss of length nn.
It is guaranteed that the sum of nn over all test cases does not exceed 2⋅1052⋅105.
Output
For each test case, output a single integer — the minimum number of operations that are needed to make the string non-decreasing.
Example
题目大意:
给定一个二进制串,我们每次操作可以选择一个i,使得第i位后(包括第i位)全部取反,问最少需要进行几次操作,可以使得整个串不下降。
解题思路一:
在纸上模拟会发现,我们考虑连续的1的段数,当连续的段数为1时,毫无疑问的,从第一个1开始操作,仅需要一次就可以满足要求,当连续1的段数cnt大于2时,我们需要(cnt - 1) * 2次操作,因为每次操作还会把后边的0变为1,则需要多进行一次操作将1变为0,特别要注意的是,如果原串最后一位是0,则需要再多一次操作,即(cnt-1)*2+1。
代码(CPP):
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 2e5 + 10;
const int INF = 0x3fffffff;
int n;
string s;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout << fixed;
cout.precision(18);
int t;
cin >> t;
while(t--)
{
cin >> n;
cin >> s;
s = " " + s;
int cnt = 0; // 连续的1有几段
for (int i = 1; i <= n; i++)
{
if(s[i] == '1')
{
cnt++;
while(s[i] == '1' && i <= n)
i++;
}
}
if(cnt == 0)
{
cout << "0\n";
continue;
}
int ans = (cnt - 1) * 2;
if(s[n] == '0')
ans++;
cout << ans << endl;
}
return 0;
}
解题思路二:
考虑连续段数,除了第一段连续的1,后边还有几段连续的1,以及连续的0,则需要进行几步。连续的0也要算上是因为对1进行操作之后,后边的0会被变为1.
代码(CPP):
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 2e5 + 10;
const int INF = 0x3fffffff;
int n;
string s;
/*
考虑连续段数,除了第一段连续的1,后边还有几段连续的1,
以及连续的0,则需要进行几步。连续的0也要算上是因为对1进行操作之后,
后边的0会被变为1.
*/
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout << fixed;
cout.precision(18);
int t;
cin >> t;
while(t--)
{
cin >> n;
cin >> s;
s = " " + s;
int i, ans = 0;
for (i = 1; i <= n; i++)
{
if(s[i] == '1')
{
break;
}
}
for (int j = i + 1; j <= n; j++)
{
if(s[j] != s[j - 1])
ans++;
}
cout << ans << endl;
}
return 0;
}