题目链接
题目翻译:
给你一个长度为n的字符串s,其中n是偶数,并且s是二进制串,即只由’0’和’1’组成。
s有n/2个’0’和n/2个’1’(n是偶数)。
在一次操作中,你可以翻转s的任意子串,一个字符串的子串指的是该字符串的一段连续的字符串。
你需要执行多少次这样的操作,使得字符串中的’0’和’1’是交替出现的,即对于所有的i,si≠si+1都成立。比如:01010101…和10101010…
解题思路:
通过看题目给出的例子可以发现,下划线上的第一个数字1是连续两个1中的第二个1,下划线上的最后一个数字0是连续两个0中的第一个0
是否可以这样理解,如果有连续的数字,就需要翻转子字符串。而显然下划线的最后一位必须和下划线的第一位不同,并且最后一位数字也是有连续的数字的,这样翻转才能做到一石二鸟,是翻转次数尽可能地少。
这样虽然讲得通,但是似乎略显麻烦。再观察观察,前三个连续的1,在进行一次翻转后,依旧有两个1是相邻的,那这两个1肯定又需要一次翻转,使之分离。是否可以这样理解,一段连续的数字,需要翻转的次数是其长度减去1的值?
并且因为字符串只由两种字符组成,所以可以只考虑1或者只考虑0。
总结一下就是,需要翻转的次数等于字符串中所有连续的1(或0)的长度减一的和。语言表达可能不太准确,具体看代码。
但是又发现第二个例子0110,如果只考虑0,结果是错的,但是只考虑1就是对的。既然这样就干脆0和1都分别单独考虑,取最大值。
代码:
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<cstdio>
#include<cmath>
#define inf 0x3f3f3f3f
using namespace std;
int main(){
// freopen("1.txt","r",stdin);
int t,n;
string s;
cin>>t;
while(t--){
cin>>n>>s;
int sum=0,sum1=0,sum2=0,flag=0;
for(int i=0;i<n;i++){
if(s[i]=='0'){
sum++;
}else{
if(sum){
sum1+=sum-1;
}
sum=0;
}
}
sum=0,flag=0;
for(int i=0;i<n;i++){
if(s[i]=='1'){
sum++;
}else{
if(sum){
sum2+=sum-1;
}
sum=0;
}
}
cout<<max(sum1,sum2)<<endl;
}
return 0;
}
总结:
事实证明,多思考思考,是可以省下很多代码的。如果按最开始的思路,我可能要写好久好久。