B. Subsequence Hate
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
Shubham has a binary string s. A binary string is a string containing only characters “0” and “1”.
He can perform the following operation on the string any amount of times:
Select an index of the string, and flip the character at that index. This means, if the character was “0”, it becomes “1”, and vice versa.
A string is called good if it does not contain “010” or “101” as a subsequence — for instance, “1001” contains “101” as a subsequence, hence it is not a good string, while “1000” doesn’t contain neither “010” nor “101” as subsequences, so it is a good string.
What is the minimum number of operations he will have to perform, so that the string becomes good? It can be shown that with these operations we can make any string good.
A string a is a subsequence of a string b if a can be obtained from b by deletion of several (possibly, zero or all) characters.
Input
The first line of the input contains a single integer t (1≤t≤100) — the number of test cases.
Each of the next t lines contains a binary string s (1≤|s|≤1000).
Output
For every string, output the minimum number of operations required to make it good.
Example
input
7
001
100
101
010
0
1
001100
output
0
0
1
1
0
0
2
Note
In test cases 1, 2, 5, 6 no operations are required since they are already good strings.
For the 3rd test case: “001” can be achieved by flipping the first character — and is one of the possible ways to get a good string.
For the 4th test case: “000” can be achieved by flipping the second character — and is one of the possible ways to get a good string.
For the 7th test case: “000000” can be achieved by flipping the third and fourth characters — and is one of the possible ways to get a good string.
大致题意:一个不包含‘010’,‘101’子串的字符串称为好的字符串。给你一个只含’0’,'1’字符的字符串,问至少需要几步操作才能变成一个好字符串。
思路:写出二进制的1~32判断是否为好的字符串还是不好的字符串,便可以发现,好的字符串有一个特点即左边全为‘0’右边全为‘1’,或者左边全为‘1’,右边全为’0‘.那么我们可以用前缀和解出这道题。
#include
#include
using namespace std;
typedef long long ll;
#define N 2e5 + 10
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
string s;
cin>>s;
int minn = 1000, tot0, tot1;
tot0 = tot1 = 0;
int len = s.size(), index = 0;
int pre0[1050] = {0}, pre1[1050] = {0}, post0[1050] = {0}, post1[1050] = {0};
if(s[0] == '0'){
pre0[0] = 1;
pre1[0] = 0;
tot0++;
}
else{
pre0[0] = 0;
pre1[0] = 1;
tot1++;
}
/*前缀和*/
for(int i = 1; i < len; i++)
{
if(s[i] == '0')
{
tot0++;
pre0[i] = pre0[i-1] + 1;
pre1[i] = pre1[i-1];
}
else
{
tot1++;
pre0[i] = pre0[i-1];
pre1[i] = pre1[i-1] + 1;
}
}
minn = min(tot0, tot1);
if(s[len - 1] == '0'){
post0[len - 1] = 1;
post1[len - 1] = 0;
tot0++;
}
else{
post0[len - 1] = 0;
post1[len - 1] = 1;
tot1++;
}
/*后缀和*/
for(int i = len - 2; i >= 0; i--)
{
if(s[i] == '0')
{
post0[i] = post0[i+1] + 1;
post1[i] = post1[i+1];
}
else
{
post0[i] = post0[i+1];
post1[i] = post1[i+1] + 1;
}
}
for(int i = 0; i < len; i++)
{
int m = max(pre0[i] + post1[i+1], pre1[i] + post0[i+1]);
minn = min(minn, len - m);
}
printf("%d\n", minn);
}
return 0;
}
我写的代码又臭又长,不过可读性还是比较强的,这里再贴一下cf出题人写的代码,他的思路是用pre0表示当前位置前(包括当前位置)的0的个数,pre1表示当前位置前(包括当前位置)的1的个数,suf0表示当前位置后(不包括当前位置)的0的个数,suf1表示当前位置后(不包括当前位置)的1的个数,要变成10或者变成01只需要计算当前位置前0有多少个(1有多少个),当前位置后1有多少个(0有多少个),即需要改变字符的个数即可
#include
using namespace std;
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define endl "\n"
#define int long long
const int N = 1e5 + 5;
int32_t main()
{
IOS;
int t;
cin >> t;
while(t--)
{
string s;
cin >> s;
int suf0 = 0, suf1 = 0;
for(auto &it:s)
{
suf0 += (it == '0');
suf1 += (it == '1');
}
int ans = min(suf0, suf1); //Make whole string 0/1
int pref0 = 0, pref1 = 0;
for(auto &it:s)
{
pref0 += (it == '0'), suf0 -= (it == '0');
pref1 += (it == '1'), suf1 -= (it == '1');
//Cost of making string 0*1*
ans = min(ans, pref1 + suf0);
//Cost of making string 1*0*
ans = min(ans, pref0 + suf1);
}
cout << ans << endl;
}
return 0;
}