这里做一个提示与证明:最终序列中的所有数还是在{-1,0,1}中。
证明:如果某个数比-1小,设第一个比-1小的数的位置是i,那么由于a_(i-1)>=-1,a_i<-1,则不满足最终序列单调不降。
如果某个数比1大,则其后的所有数都大于等于2,设第一个比1大的数的位置是i,则a_(i-1)=1。 要让第i+1个位置上的数比第i个位置上的数大于或等于,如果第i个位置上的数是x(x>=2),则根据a_(i+1)初始的情况作分类讨论:
a_(i+1)=-1,需要的次数至少是ceil( (1+x)/x )>=2。
a_(i+1)=0,需要的次数至少是ceil( x/x )=1。
a_(i+1)=1,需要的次数至少是ceil( (x-1)/x )=1。
接着对比如果x=1是什么情况:
a_(i+1)=-1,需要的次数至少是2。
a_(i+1)=0,需要的次数至少是1。
a_(i+1)=1,需要的次数至少是0。
可见,我们把x从>=2改成1,不仅从(i-1)到i所需次数减少,从i到(i+1)所需的最少次数也减少了,如果取了这个最少次数,那么a_(i+1)最终也会变为1,那么要满足让初始的a_(i+2)变得>=a_(i+1),所需的最少次数也比原来少(因为a_(i+1)原本>=2),而且这个最少次数也应该取到,因为a_(i+2)=1更优。这样,把第一个比1大的数改成1,要让所需次数更少,可以推出后面的所有数都是1。所以最终序列中最大的数不超过1。
之后可以定义状态dp[i][j]表示第i个数最终变成j,前缀序列1到i需要的最少次数。
/*
模板符合C++98标准
upd:25.08.07
*/
//输入输出相关头文件
#include<iostream>
#include<cstdio>
//数据类型和STL
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<vector>
#include<bitset>
#include<stack>
#include<utility>
//其他
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<iomanip>
#include<climits>
#include<limits>
#include<sstream>
using namespace std;
typedef long long ll;
#define fastio ios::sync_with_stdio(0);cin.tie(0);
#define filein freopen("D:/in.txt","r",stdin);
#define fileout freopen("D:/out.txt","w",stdout);
const ll maxn=1e6+5,inf=0x3f3f3f3f3f3f3f3fLL;
ll dp[maxn][5],a[maxn];
ll n;
int main()
{
cin>>n;
for(ll i=1;i<=n;i++) cin>>a[i];
//初始化dp数组
for(ll i=1;i<=n;i++) {
dp[i][0]=dp[i][1]=dp[i][2]=inf;
}
dp[1][a[1]+1]=0;
for(ll i=2;i<=n;i++) {
if(a[i]==0) {
dp[i][0]=min(dp[i][0],dp[i-1][0]+1);
dp[i][1]=min({dp[i][1],dp[i-1][1],dp[i-1][0]});
dp[i][2]=min(dp[i][2],dp[i-1][2]+1);
}else if(a[i]==-1) {
dp[i][0]=min(dp[i][0],dp[i-1][0]);
//dp[i][1]=min(dp[i][1],dp[i-1][2]+1);
dp[i][2]=min(dp[i][2],dp[i-1][2]+2);
}else if(a[i]==1) {
dp[i][0]=min(dp[i][0],dp[i-1][0]+2);
dp[i][1]=min(dp[i][1],dp[i-1][0]+1);
dp[i][2]=min({dp[i][2],dp[i-1][0],dp[i-1][1],dp[i-1][2]});
}
}
ll ans=min({dp[n][0],dp[n][1],dp[n][2]});
if(ans==inf) cout<<"BRAK"<<"\n";
else cout<<ans<<"\n";
return 0;
}
}