Binary Subsequence Rotation 解题报告

Naman has two binary strings s s s and t t t of length n n n (a binary string is a string which only consists of the characters “0” and “1”). He wants to convert s s s into t t t using the following operation as few times as possible.

In one operation, he can choose any subsequence of s s s and rotate it clockwise once.

For example, if s = 1110100 s=1110100 s=1110100, he can choose a subsequence corresponding to indices (11-based) { 2 , 6 , 7 } \left\{2,6,7\right\} {2,6,7} and rotate them clockwise. The resulting string would then be s = 1010110 s=1010110 s=1010110.

A string a a a is said to be a subsequence of string b b b if a a a can be obtained from b b b by deleting some characters without changing the ordering of the remaining characters.

To perform a clockwise rotation on a sequence c c c of size k k k is to perform an operation which sets c 1 : = c k , c 2 : = c 1 , c 3 : = c 2 , … , c k : = c k − 1 c_1:=c_k,c_2:=c_1,c_3:=c_2,…,c_k:=c_{k−1} c1:=ck,c2:=c1,c3:=c2,,ck:=ck1 simultaneously.

Determine the minimum number of operations Naman has to perform to convert s s s into t t t or say that it is impossible.

这是一道非常好的题。

首先对于 s i = t i s_i=t_i si=ti的部分我们不必进行处理,也就是说取子数列的时候可以略去它们。

那么对于剩下 s i ≠ t i s_i\not=t_i si=ti的部分怎么保证操作次数最小呢?

我们可以发现当子数列 0 , 1 0,1 0,1交替出现,即"01010…"或"10101…"时操作最优,因为当子数列出现连续多个 0 0 0 1 1 1时,只有最左边的0或1得到了有效的替换,这和舍去这一段而仅取其一的效果是等价的。

因此,不断找出连续的交错数列直到符合配对;由于每个交错数列旋转一次后便可翻转,即成功配对,因此答案为交错数列的个数。

而怎么求交错数列的个数呢?我们如果把不匹配的 s i , t i s_i,t_i si,ti分别用:

s i = 1 , t i = 0 , c i : = 1 s_i=1,t_i=0,c_i:=1 si=1,ti=0,ci:=1

s i = 0 , t i = 1 , c i : = − 1 s_i=0,t_i=1,c_i:=-1 si=0,ti=1,ci:=1

来表示的话,交错数列的个数就是最长一段 c i = 1 c_i=1 ci=1或最长一段 c i = − 1 c_i=-1 ci=1的长度,这是因为对于连续的一段1或-1,它们不可能在同一段交错级数,而必须把它们拆开。

那么问题转化为最大连续子序列和和最小连续子序列和的绝对值得最大值。

代码:

#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
 int n;
 string s;
 string t;
 int c[1000001];
int main()
{
 scanf("%d",&n);
 cin >> s;
 cin >> t;
 int a = 0;
 int b = 0;
 for (int i = 0;i < s.size();i ++)
  if (s[i] == '0')
   a ++;
 for (int i = 0;i < t.size();i ++)
  if (t[i] == '0')
   b ++;
 if (a != b)
 {
  printf("-1");
  return 0;
 }
 for (int i = 0;i < s.size();i ++)
  if (s[i] == t[i])
   c[i] = 0;
  else if (s[i] == '1')
   c[i] = 1;
  else c[i] = -1;
 int ans = 0;
 int now = 0;
 for (int i = 0;i < s.size();i ++)
 {
  now = max(c[i],now + c[i]);
  ans = max(ans,now);
 }
 now = 0;
 int ans2 = 0;
 for (int i = 0;i < s.size();i ++)
 {
  now = min(c[i],now + c[i]);
  ans2 = min(ans2,now);
 }
 ans = max(-ans2,ans);
 printf("%d",ans);
 return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值