翻译:
这是这个问题的难解版本。两个版本之间的唯一区别是,较难的版本额外要求子段的最小数量。
Tokitsukaze有一个长度为𝑛的二进制字符串𝑠,仅由0和1组成,𝑛是偶数。
现在Tokitsukaze将𝑠划分为连续子段的最小数目,对于每个子段,每个子段中的所有位都是相同的。之后,如果所有子段的长度相等,则认为𝑠是好的。
例如,如果𝑠为“11001111”,则将其分为“11”、“00”和“1111”。它们的长度分别是2、2、4,都是偶数,所以“11001111”是好的。再例如,如果𝑠为“1110011000”,则将其分为“111”、“00”、“11”和“000”,它们的长度分别为3,2,2,3。显然,“1110011000”不好。
Tokitsukaze想通过改变𝑠中一些位置的值来使𝑠变得更好。具体来说,她可以执行任意次数的操作:将𝑠𝑖的值更改为'0'或'1'(1≤𝑖≤𝑛)。你能告诉她让𝑠好起来的最少操作次数吗?同时,她还想知道在所有操作次数最少的解中,𝑠可以被划分的子段的最小数目。
输入
第一个包含一个正整数𝑡(1≤𝑡≤10000)——测试用例的数量。
对于每个测试用例,第一行包含单个整数𝑛(2≤𝑛≤2⋅105)—𝑠的长度,保证𝑛为偶数。
第二行包含长度为𝑛的二进制字符串𝑠,仅由0和1组成。
保证𝑛在所有测试用例上的总和不超过2⋅105。
输出
对于每个测试用例,打印带有两个整数的一行—使𝑠正常运行的最小操作数,以及𝑠在具有最小操作数的所有解中可以划分的最小子段数。
例子
inputCopy
5
10
1110011000
8
11001111
2
00
2
11
6
100110
outputCopy
3 - 2
0 3
0 1
0 1
3个1
请注意
在第一个测试用例中,使𝑠变得良好的方法之一如下所示。
将𝑠3,𝑠6,𝑠7改为“0”,之后𝑠变成“1100000000”,它可以分为“11”和“00000000”,长度分别为2和8,其子段数为2。还有操作3次使𝑠变好的方法,如“1111110000”、“1100001100”、“1111001100”,它们的子段数分别为2、4、4。我们很容易发现,在所有具有最小操作数的解中,子段数的最小值是2。
在第二个、第三个和第四个测试用例中,𝑠最初是很好的,因此不需要操作。
思路:改变最小操作,可以很明显的得知,最小操作数就是判断相邻,因为n保证了是偶数,所以我们可以直接判断,两个相邻不同,我们可以修改其中的任意一个,所以我们可以改成00 或11,有我们将其定义为x,来作为可以任意改动过的标记。因为如果任意两个相同的拼到一起,就可以减少段数,因为段数如果不是全相同就是以2为底的。之后我们遍历标记,最后在记录一下连续段就可以了,最后防止是0取一个max。
代码:
#include <iostream>
#include <algorithm>
#include <string.h>
#include <string>
#include <math.h>
#include <stdio.h>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<tuple>
#include<numeric>
#include<stack>
using namespace::std;
typedef long long ll;
int n,t;
inline __int128 read(){
__int128 x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){
if(ch == '-')
f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9'){
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
inline void print(__int128 x){
if(x < 0){
putchar('-');
x = -x;
}
if(x > 9)
print(x / 10);
putchar(x % 10 + '0');
}
string s;
void solv(){
cin>>n>>s;
ll an=0;
for (int i =0; i<n; i+=2) {
if (s[i]!=s[i+1]) {
s[i]=s[i+1]='x';
an++;
}
}
printf("%lld ",an);
an=0;
char now='l';
for (int i =0; i<n; i++) {
if(s[i]=='x')continue;
if (now!=s[i]) {
now=s[i];
an++;
}
}
printf("%lld\n",max(an,1ll));
}
int main(){
ios::sync_with_stdio(false);
cin.tie(); cout.tie();
cin>>t;
while (t--) {
solv();
}
return 0;
}