注:解法有参考官方题解
题目描述
小芳拿到了一个仅由字符 0 和 1 组成的长为 n 的字符串 s,他可以进行任意次如下操作: 选择 s 的一个非空子序列 [1] ,该子序列任意两个相邻元素都不相同,将该子序列进行 01 反置 [2] 。 小芳想知道,最少需要多少次操作才能使得 s 中任意两个相邻元素都不相同?
【名词解释】 子序列 [1] :从原序列中删除任意个(可以为零,也可以为全部)元素,且保持剩余元素相对顺序不变得到的新序列。 01 反置 [2] :同时将字符串中的 0 变成 1, 1 变成 0。
题解如下:
题目要求最后要使s中任意两个相邻元素都不相同,那么s最后只可能时01010101的形式或10101010的形式,我们只需要把和01010101(10101010同理)不同的部分抽出来(设抽出来的部分为str),看最少需要几次可以把抽出来的部分清空,最多需要str.size()次,但是我们压缩所需要的次数(每次可按010101...01,或101010...1010的形式减少多个),但这不意味着最少需要的次数即为str中最长连续的字串的长度,具体看例子:1111100011111,如果抽了三次101,那么它会变成1111,这意味着我们还需要4次才能解决,而最长连续字串仅为5,故不成立,经过观察,我们可以发现,需要的最少次数即为区间最大子段和,对str扫两遍,一遍str[i]为1时加1,为0时减一,第二遍相反,每一遍取区间最大字段和,最后输出两遍中较小的即可。 代码如下:
ll F(string s)
{
ll cnt=0,num,mx=0;
for(ll i=0;i<(ll)s.size();i++)
{
if(s[i]=='1')cnt++;
else cnt--;
mx=max(mx,cnt);
if(cnt<0)cnt=0;
}
num=mx;
mx=cnt=0;
for(ll i=0;i<(ll)s.size();i++)
{
if(s[i]=='0')cnt++;
else cnt--;
mx=max(mx,cnt);
if(cnt<0)cnt=0;
}
return max(num,mx);
}
void solve()
{
ll n,mx=1,cnt=1,ans;
string str,s1;
cin>>n>>str;
for(ll i=0;i<n;i++){
if((i&1)&&str[i]=='1')s1+=str[i];
if(!(i&1)&&str[i]=='0')s1+=str[i];
}
ans=F(s1);
s1="";
for(ll i=0;i<n;i++){
if((i&1)&&str[i]=='0')s1+=str[i];
if(!(i&1)&&str[i]=='1')s1+=str[i];
}
ans=min(ans,F(s1));
cout<<ans<<endl;
}
如有错误烦请指正谢谢

京公网安备 11010502036488号