题目描述
小美定义一个 01 串的权值为:每次操作选择一位取反,使得相邻字符都不相等的最小操作次数。
例如,"10001"的权值是 1,因为只需要修改一次:对第三个字符取反即可。
现在小美拿到了一个 01 串,她希望你求出所有非空连续子串的权值之和,你能帮帮她吗?
输入描述:
一个仅包含'0'和'1'的字符串,长度不超过 2000。
输出描述:
所有非空子串的权值和。
输入
10001
输出
8
说明
长度为 2 的子串中,有 2 个"00"的权值是 1。 长度为 3 的 3 个子串权值都是 1。 长度为 4 的 2 个子串权值都是 1。 长度为 5 的 1 个子串权值是 1。 总权值之和为 2+3+2+1=8
解题思路
这道题是01串问题,这里我们直接采用遍历的方式,记录字符串的每一个子串的权值,子串直接两层for循环,第一层枚举子串的开头字符,第二层枚举子串的每一个字符。接下来就是这个权值的算法,因为要使每两个相邻字符不一样,所以只有两种可能的情况,0开头的(010101...)或1开头的(101010...),我们只需要模拟这两种修改方式并统计需要修改次数即可。
用ans1表示以0开头的子串,偶数位上的数都应该是0,用ans2表示以1开头的子串,偶数位上的数都应该是1
我们取以0开头的ans1和以1开头的ans2的最小值即可。
//开头的位置,下标0,2,4...
if (j % 2 == 0)
{
if (str[j] == '0') ans2++;
else ans1++;
}
else//第二的位置,下标1,3,5...
{
if (str[j] == '0')
{
if (str[j] == '0') ans1++;
else ans2++;
}
}
ans += min(ans1, ans2);
AC代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
#define int long long
#define endl '\n'
typedef long long ll;
const int N = 210;
signed main()
{
string str;
cin >> str;
int ans = 0;
for (int i = 0; i < str.size(); i++)
{
int ans1 = 0, ans2 = 0;
for (int j = i; j < str.size(); j++)
{
//开头的位置,下标0,2,4...
if (j % 2 == 0)
{
if (str[j] == '0') ans2++;
else ans1++;
}
else//第二的位置,下标1,3,5...
{
if (str[j] == '0')
{
if (str[j] == '0') ans1++;
else ans2++;
}
}
ans += min(ans1, ans2);
}
}
cout << ans;
return 0;
}