CodeForces - 1370E Binary Subsequence Rotation(思维)

题目链接:点击查看

题目大意:给出一个只由 0 或 1 组成的字符串 s ,和一个字符串 t ,问 s 至少需要操作多少次,才能变为 t,每次操作是:可以选择字符串 s 中的一个子序列,使得他们全部向右移动一个单位,如:s = 1\textbf{1}101\textbf{00},选择的子序列为位置\{2, 6, 7 \},经过操作后 s 就变为了 s = 1\textbf{0}101\textbf{10}

题目分析:很显然的两个结论是,如果字符串 s 和字符串 t 中 1 的数量或者 0 的数量不相等,那么输出 -1 ,还有一点就是,如果字符串 s 和字符串 t 中的某一位置 s[ i ] == t[ i ] ,则这个位置无需操作,可以视为被删除就好了

接下来考虑贪心,子序列的长度肯定得大于等于 2 ,稍微举举例子不难发现,每次操作只能选择偶数串的 0101... 或者 1010...,举个反例就是,如果选择的 s 为 011,那么经过操作后变为了 101,第三个位置没有变化,所以选不选第三个位置没有影响,同理得出每次只能选择偶数个的 01 交替的子序列进行操作才是具有贡献的

然后贪心放,就拿s = 110100t=001011为例,此时已经将所有 s[ i ] == t[ i ] 的位置都删除掉了,从 1 ~ n 遍历一遍字符串,当遍历到第一个位置时,s[ 1 ] == 1 ,所以 ans++ ,另外这里有一个单独的 1,到了第二个位置时,s[ 2 ] == 1,所以仍然让 ans++,此时有两个单独的 1 ,到了第三个位置,此时 s[ 3 ] == 0 ,因为前面已经有两个单独的 1 了,所以我们贪心让这个 0 与第一个 1 匹配,此时 ans 不变,我们有一个 “10” 串和一个 “1” 串,到了第四个位置,此时 s[ 4 ] == 1 ,因为此时第一个串中可以接一个 1 了,所以我们就可以直接将当前的 1 与 “10” 匹配,此时有一个 “101” 串和一个 “1” 串,剩下的两个位置都是 0 ,我们直接让其与两个串匹配即可,即最后的两次操作分为 “1010” 和 “10” ,答案为 2 是最优的

再看一个例子,这样我就只给出字符串 s 了,如果s=1001,按照上面的贪心,当匹配完前三个位置后,我们得到了两个串:“10” 和 “0” ,到了第四个串的 s[ 4 ] == 1,按理说和第一个串或者第二个串都是可以匹配的,但是我们发现如果和第一个串匹配的话,最后就无法形成偶数个 1010... 了,所以此时应该选择其与第二个串匹配

知道原理后 O( n ) 去模拟就好了

代码:
 

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
using namespace std;

typedef long long LL;

typedef unsigned long long ull;

const int inf=0x3f3f3f3f;

const int N=1e6+100;

char s[N],t[N];

int main()
{
#ifndef ONLINE_JUDGE
//  freopen("input.txt","r",stdin);
//  freopen("output.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	int n;
	scanf("%d%s%s",&n,s+1,t+1);
	int sum=0,mmax=0,mmin=0;
	for(int i=1;i<=n;i++)
	{
		sum+=s[i]-t[i];
		mmax=max(mmax,sum);//记录最多有多少个连续的“1”需要让 ans++
		mmin=min(mmin,sum);//记录最多有多少个连续的“0”需要让 ans++
	}
	printf("%d\n",sum?-1:mmax-mmin);














    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_45458915/article/details/106909453