题解 P3558 【[POI2013]BAJ-Bytecomputer】
这题贪心也能做呢!
在机房学长&大佬 @jeffqi 的指导下,用贪心做出来了!。
第一步
首先明确,这个队列只有
假设给出这么一个例子:
a[3]={1,1,-1}
如果我们要使
-
直接用
a[1] 对a[2] 进行操作 , 需要2 次操作使a[2]=1\geq a[1]=1 。 -
假设我们花费一步对
a[1] 进行操作使序列变为\{1,2,-1\} , 然后再对a[2] 进行操作 , 我们发现我们仍然需要2 次操作才能使a[2]=3\geq a[1]=2 ,而再进一步地修改显然也需要更多步数,因此永远保持序列中只存在1,0,-1 才是性价比最高的做法。
第二步
其次,我们发现,如果队列中只存在
我们发现,以
对于 1 来说:
如果一个序列(或子序列)以
a[6]={1,-1,0,1,-1,0}
我们发现我们无法改变
对于 0 来说:
如果一个序列(或子序列)以
a1[6]={0,0,-1,-1,1,-1}
a2[6]={0,0,1,0,-1,1}
我们这时已经失去了第一层阶梯,由于第一个数是不允许被改变的,所以我们这时仅允许
如果我们这时在一串
而如果我们遇到的第
所以对于
对于 -1 来说:
对于
我们可以直接从前往后扫。如果遇到的是
而变为
然后再考虑把前面的每一个数都变为
上代码:
#include<bits/stdc++.h>
#define rep(a,b,c) for(int c=(a);c<=(b);++c)
#define drep(a,b,c) for(int c=(a);c>=(b);--c)
#define INF 0x3f3f3f3f
#define N 1000005
using namespace std;
inline int read()
{
long long ans=0;bool f=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=getchar();}
while(ch>='0'&&ch<='9'){ans=(ans<<1)+(ans<<3)+(ch^48);ch=getchar();}
if(f) return -ans; return ans;
}
int n,a[N],suf[N],nxt[N];
int main()
{
n=read();int las=n+1;
rep(1,n,i)a[i]=read();
drep(n,1,i)
{
suf[i]=suf[i+1]+(1-a[i]);
nxt[i]=las;if(a[i])las=i;
}
if(a[1]==1){printf("%d\n",suf[1]);return 0;}
if(!a[1])
{
if(a[nxt[1]]==-1){puts("BRAK");return 0;}
printf("%d\n",suf[nxt[1]]);return 0;
}
int mn=INF,cnt=0;
rep(1,n,i)
{
cnt+=a[i]+1;
if(a[nxt[i]]!=-1)mn=min(mn,cnt+suf[nxt[i]]);
if(i<n&&a[i+1]==1)mn=min(mn,cnt+1+suf[nxt[i+1]]);
}
printf("%d\n",mn);
}
用时:
代码长度: 非常好写!