标签:最大 并且 改变 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