小美的01串翻转

366 阅读2分钟

题目描述

小美定义一个 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;
}