问题 F: 翻硬币
时间限制: 1.000 Sec 内存限制: 128 MB
提交 状态
题目描述
小 Q 面前的桌子上有 N 个硬币,0 表示正面,1 表示反面,现在他有一次机会可以选择一个 ai~bi 的段,把这个段的硬币都翻转一面,他现在想知道 N 个硬币中最多可以有多少个硬币正面朝上。
输入
第一行一个整数 N,表示桌子上有 N 个硬币。
第二行为 N 个 0 和 1,表示硬币 i 的状态。其中 0 表示正面,1 表示反面。
输出
第一行有一个整数,表示翻转后最多有多少个硬币正面朝上。
样例输入 Copy
4 1 0 1 1
样例输出 Copy
3
提示
【样例解释】
将 1 0 1 1 可以改为 0 1 0 0 或 1 0 0 0
【数据范围】
30%的数据 1 <= N <=100
60%的数据 1 <= N <=104 。
100%的数据 1 <= N <=106。
#include<bits/stdc++.h>
using namespace std;
int a[1000005];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
int L=0,R=0;
int l=1,r=1;
int maxn=0;
while(r<=n){
while(a[l]==0&&l<=n){//先判断边界和一开始是0的不要
l++;
}
r=l;//把r也移过来
if(r>n){//判断边界
break;
}
int s=0;//这个是存这个区间翻出来会加多少贡献
while(r<=n&&s>=0){//s小于0了就说明这个区间翻了也加不了
if(a[r]==0){
s--;
}
else{
s++;
}
if(s>=maxn){//把这个区间里面最大可以加的存起来
maxn=s;
R=r;//把最大的l,r都存起来
L=l;
}
r++;
}
if(r>n){//r到头了
if(s>=maxn){
maxn=s;//还能加就存起来
L=l;
R=n;
}
break;
}
else if(s>=maxn){//r没到头还能加也存起来
maxn=s;
L=l;
R=r;
}
while(a[l]==1&&l<=n){//这个就是r搞完以后 发现还可以更新l就把l在更新然后再继续
l++;
}
}
int tot=0;
for(int i=L;i<=R;i++){//把刚刚存的最大的l和r拿出来翻
if(a[i]==1){
a[i]=0;
}
else a[i]=1;
}
for(int i=1;i<=n;i++){
if(a[i]==0){
tot++;
}
}
cout<<tot;
return 0;
}
本人也是个菜鸡 这个是一个大佬的的ac代码 我就看懂了然后加上注释