求思路,附加题目题解:
选定一段区间 [l,r],使得区间外的 1 的数量和区间内的 0 的数量的最大值尽可能小。
贪心一下发现,最优的区间两个端点一定是 1,可以反证,以 1 两边的一个或连续一段 0 结尾,显然不如回退到 1 的位置来减少区间内 0 的数量。因此,记录所有 1 的位置下标,用前缀和维护区间 0 和 1 的数量,又因为对于每一个左端点,删掉的 1 非严格递减,区间内 0 非严格递增,用二分求解对于每一个左端点的最优右端点即可。(找到删掉的 1 恰好小于保留的 0 和恰好大于等于的位置,比较那个更优)。
离离原上谱代码:
#include<bits/stdc++.h>
using namespace std;
int n,len,cnt,num,a[2000010],sum[2000010],ans=1e9,l,r;
string s;
int f(int x){//二分这里完全打错了
int ll=x,rr=r,mid;
while(ll<rr){
mid=(ll+rr)/2;
if(mid-(sum[mid+1]-sum[x+1])-x<=rr-(sum[rr+1]-sum[x+1])-x){
rr=mid;
}else{
ll=mid+1;
}
}
return min(ll-(sum[ll+1]-sum[x+1])-x,rr-(sum[rr+1]-sum[x+1])-x);
}
int main(){
cin>>s;
n=s.length();
for(int i=0;i<n;i++){
sum[i+1]=sum[i]+s[i]-'0';
if(s[i]=='1'){
a[++cnt]=i;
}
}
l=a[1],r=a[cnt];
for(int i=l;i<=r;i++){
if(f(i)<ans)//这里判断也有问题
ans=f(i);
}
cout<<ans;
return 0;
}
//云若浮沫夕阳下