D. Balanced String

D. Balanced String

You are given a binary string s (a binary string is a string consisting of characters 0 and/or 1).

Let's call a binary string balanced if the number of subsequences 01 (the number of indices i and j such that 1i<jn, si=0 and sj=1) equals to the number of subsequences 10 (the number of indices k and l such that 1k<ln, sk=1 and sl=0) in it.

For example, the string 1000110 is balanced, because both the number of subsequences 01 and the number of subsequences 10 are equal to 6. On the other hand, 11010 is not balanced, because the number of subsequences 01 is 1, but the number of subsequences 10 is 5.

You can perform the following operation any number of times: choose two characters in s and swap them. Your task is to calculate the minimum number of operations to make the string s balanced.

Input

The only line contains the string s (3|s|100) consisting of characters 0 and/or 1.

Additional constraint on the input: the string s can be made balanced.

Output

Print a single integer — the minimum number of swap operations to make the string s balanced.

Examples

input

101

output

0

input

1000110

output

0

input

11010

output

1

input

11001100

output

2

Note

In the first example, the string is already balanced, the number of both 01 and 10 is equal to 1.

In the second example, the string is already balanced, the number of both 01 and 10 is equal to 6.

In the third example, one of the possible answers is the following one: 11010 01110. After that, the number of both 01 and 10 is equal to 3.

In the fourth example, one of the possible answers is the following one: 11001100 11001010 11000011. After that, the number of both 01 and 10 is equal to 8.

 

解题思路

  这题最关键的地方是要发现不管怎么交换字符,字符串中0110的总数总是不变。

  首先字符串中大小为2的子序列无非就只有如下4种:00110110。可以发现无论我们怎么交换,字符串中01的数量总是不变,因此0011的总和也总是不变。假设字符串中0的数量为s01的数量为s1,那么s0(s01)2+s1(s11)2就是定值,也意味着0110的数量也总是不变,因为m=n(n1)2(s0(s01)2+s1(s11)2)也是一个定值。由于题目保证一定可以得到平衡字符串,因此m必然是偶数,意味着我们要通过最小的交换次数使得字符串中0110的数量都等于m2

  问题可以等价成求最小的交换次数使得字符串中子序列01的数量恰好为m2。可以发现交换相同字符是没有意义的,因此我们每次都应该交换01,相应的就会有两个不同位置的字符发生改变。为了方便我们把每一次的交换都记到01的位置,也就是说如果要把某个位置的01,那么交换的次数就加1,而10的位置就不再统计(保证0110出现的次数相同)。

  因此可以定义状态f(i,c0,j)表示交换后前i个字符中有c0001的数量为j的所有方案中,交换次数的最小值。根据第i个字符是0还是1进行状态划分。如果si本身就是0,那么就有状态转移方程

f(i,c0,j)=min{f(i1,c01,j),si0f(i1,c0,jc0)+1,si1

  如果si本身就是1,那么就有状态转移方程

f(i,c0,j)=min{f(i1,c0,jc0),si1f(i1,c01,j),si0

  综合一下就有f(i,c0,j)=min{f(i1,c01,j),f(i1,c0,jc0)+[si==0]}

  最后答案就是f(n,s0,m)

  AC代码如下,时间复杂度为O(n4)

复制代码
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 typedef long long LL;
 5 
 6 const int N = 110, M = N * N / 4;
 7 
 8 char s[N];
 9 int f[N][N][M];
10 
11 int main() {
12     scanf("%s", s + 1);
13     int n = strlen(s + 1);
14     int s0 = 0, s1 = 0;
15     for (int i = 1; i <= n; i++) {
16         if (s[i] & 1) s1++;
17         else s0++;
18     }
19     int m = n * (n - 1) / 2 - s0 * (s0 - 1) / 2 - s1 * (s1 - 1) / 2 >> 1;
20     memset(f, 0x3f, sizeof(f));
21     f[0][0][0] = 0;
22     for (int i = 1; i <= n; i++) {
23         for (int j = 0; j <= min(i, s0); j++) {
24             for (int k = 0; k <= m; k++) {
25                 if (j) f[i][j][k] = f[i - 1][j - 1][k];
26                 if (k >= j) f[i][j][k] = min(f[i][j][k], f[i - 1][j][k - j] + (s[i] + 1) % 2);
27             }
28         }
29     }
30     printf("%d\n", f[n][s0][m]);
31     
32     return 0;
33 }
复制代码

 

参考资料

  Educational Codeforces Round 153 Editorial:https://codeforces.com/blog/entry/119504

  Educational Codeforces Round 153 (Rated for Div. 2) 详细题解(A~D):https://zhuanlan.zhihu.com/p/650743034

posted @   onlyblues  阅读(72)  评论(5编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
历史上的今天:
2022-09-05 Meeting Rooms III
2022-09-05 Number of Ways to Reach a Position After Exactly k Steps
Web Analytics
点击右上角即可分享
微信分享提示