码迷,mamicode.com
首页 > 其他好文 > 详细

题解 CF1370E 【Binary Subsequence Rotation】

时间:2020-07-05 10:37:12      阅读:46      评论:0      收藏:0      [点我收藏+]

标签:最大   并且   改变   time   序列   ++   ace   定义   pause   

题目大意

题目描述

给定两个长度为\(n\)\(01\)\(a\)\(b\),要求串\(a\)的任意子序列经过若干次“旋转”操作变为串\(b\)

对于一次“旋转操作”我们这样定义:
如果我们要旋转的序列为

\(c_1,c_2,c_3,c_4,c_5...c_n\)

那么旋转之后的序列为\(c_n,c_1,c_2,c_3,c_4...c_{n-1}\)

例如对于\(s=1110100\)

如果我们旋转的子序列的下标为\({2,6,7}\)(从\(1\)开始)

那么旋转之后的串为$1010110 $

求至少进行多少次“旋转”操作,能够把串\(a\)变成串\(b\)

输入格式

输入一共三行

第一行输入一个整数\(n(1≤n≤10^6)\)
第二行输入串\(a\)

第三行输入串\(b\)

输出格式

输出为\(1\)行,为最小的操作次数

思路

首先,如果要求我们改变的次数最小,那么我们就只改变\(a\)\(b\)中不相同的元素。

设集合\(c\)\(a\)中与\(b\)中的元素不同的元素,并且对于每个元素其值等于\(a\)的值。

而对于\(c\)中的元素而言,每一对不同的\(1\)\(0\)都可以进行一次“旋转”操作,我们可以看作其两个元素进行交换。

而若干个元素的“旋转”操作可以看作若干次“交换”操作

因此如果\(c\)当中的\(1\)\(0\)的个数不同是一定不能将\(a\)变为串\(b\)

而现在,我们的目标为用尽量少的操作使得\(c\)中的元素全部取反(即\(1\)变成\(0\)\(0\)变成\(1\)

那么我们每次进行旋转操作的序列一定是形如\(010101\)\(101010\)这样的序列(必须为偶数位)

如果我们进行旋转操作的序列为形如\(111000\)这样的序列,那么就等价于我们进行三次\(10\)这样的旋转操作

那么我们要使得进行的操作次数尽量少,即每次使得我们选的子序列尽量的长

那么我们每进行一次操作就会使得和最大的子段的和减一,即每进行一次操作都能使得\(max(\sum_{i=l}^r\left | c_i \right |)\)减一

证明:

假设子段\([l,r]\)的和为正数,那么子段两边的元素一定是\(-1\),否则\(\sum_{i=l}^r\left | c_i \right |\)可以更大。

同理\(c[l]\)\(c[r]\)必然是\(1\),否则缩小区间范围,一定可以更大。

设该子段中一共有\(k\)\(1\),长度为\(m\),那么该子段的\(-1\)的个数为\(m-k\)

那么在该子段外至少有\(2\times k -m\)\(-1\)

对于其中的\(-1\),我们至多\(m-k\)次就可以将所有的\(-1\)\(1\)(即所有的\(-1\)全都挨在一起的情况)

而对于每次操作,我们选择的\(1\)的个数比\(-1\)的个数多一定更优

因为我们当前子段的和是最大的,且为正,因此\(1\)的个数必然比\(-1\)的个数多

考虑反证

如果我们选的\(-1\)\(1\)多的话,那么在当前子段至多选

\(2\times m-2\times k-1\)个元素

如果我们\(1\)的个数比\(-1\)的个数多,那么当前子段至多选

\(2\times m-2\times k+1\)个元素

而对于外面的元素,如果排序方式改变最多损失两个元素

因此至少不会变坏,且会更优

如果我们\(-1\)\(p\)个,那么\(1\)必然会选\(p+1\)

那么,其减少了\(1\)

如果到最后的序列不存在\(-1\),那么每次我们至少可以从当前序列中选出一个\(1\)取反,因为在该子段外至少有\(2\times k -m\)\(-1\)

因此,每次操作我们都可以使得\(max(\sum_{i=l}^r\left | c_i \right |)\)减一

并且,因为其和最大,所以能够确保每次操作,都能够作用于当前子段

那么,当\(max(\sum_{i=l}^r\left | c_i \right |)\)减为\(0\)时,即最小操作次数。

答案即为\(max(\sum_{i=l}^r\left | c_i \right |)\)

\(QED\)

而我们可以用下面代码\(O(n)\)的求出上述式子

#include <iostream>
 
using namespace std;
 
const int maxn = 1e6 + 10;
 
char a[maxn],b[maxn];
 
int c[maxn],n;
 
 
int get(int x){
	int cur = 0,res = 0;
	for (int i = 0; i < n; i++){
		cur += x * c[i];
		res = max(res,cur);
		if (cur < 0) cur = 0;
	}
	return res;
}
 
int main(){
	cin >> n >> a >> b;
	int s0 = 0,s1 = 0;
	for (int i = 0; i < n; i++){
		if (a[i] != b[i] && a[i] == ‘1‘){ 
			c[i] = 1;
			s1++;
		}
		if (a[i] != b[i] && a[i] == ‘0‘){ 
			c[i] = -1;
			s0++;
		}
	}
	if (s1 != s0){
		cout << -1;
		//system("PAUSE");
		return 0;
	}
	cout << max(get(1),get(-1));
	//system("PAUSE");
	return 0;
}

题解 CF1370E 【Binary Subsequence Rotation】

标签:最大   并且   改变   time   序列   ++   ace   定义   pause   

原文地址:https://www.cnblogs.com/wxy-max/p/13237713.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!