[POI2013]Bajtokomputer
题目大意:
给定一个长度为(n(nle10^6))的由({-1,0,1})组成的序列,你可以进行(A_i+=A_{i-1})这样的操作,问通过若干次操作能否使其变成不降序列。若果能,求最小操作次数。
思路:
显然若能通过若干次操作使其变成不降序列,则一定存在一种方案使得最后(A_iin{-1,0,1})。
(f_{i,j})表示前(i)个数,最后一个数为(j),能构成不降序列的最小操作次数,分不操作、操作(1)次、操作(2)次转移即可。
时间复杂度(mathcal O(n))。
源代码:
#include<cstdio>
#include<cctype>
#include<climits>
#include<algorithm>
inline int getint() {
register char ch;
register bool neg=false;
while(!isdigit(ch=getchar())) neg|=ch=='-';
register int x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return neg?-x:x;
}
const int N=1e6+1;
int a[N],f[N][3];
int main() {
const int n=getint();
for(register int i=1;i<=n;i++) {
a[i]=getint();
f[i][0]=f[i][1]=f[i][2]=INT_MAX;
for(register int j=-1;j<=1;j++) {
if(f[i-1][j+1]==INT_MAX) continue;
if(a[i]>=j) f[i][a[i]+1]=std::min(f[i][a[i]+1],f[i-1][j+1]);
if(i!=1&&a[i]!=j&&a[i]+j>=j) f[i][a[i]+j+1]=std::min(f[i][a[i]+j+1],f[i-1][j+1]+1);
if(i!=1&&a[i]+j*2>=j) {
if(a[i]+j*2<-1||a[i]+j*2>1) continue;
f[i][a[i]+j*2+1]=std::min(f[i][a[i]+j*2+1],f[i-1][j+1]+2);
}
}
}
int ans=INT_MAX;
for(register int i=0;i<=2;i++) ans=std::min(ans,f[n][i]);
if(ans==INT_MAX) {
puts("BRAK");
return 0;
}
printf("%d
",ans);
return 0;
}