P3558 [POI2013]BAJ-Bytecomputer
题目描述
给一个只包含\(-1,0,1\)的数列,每次操作可以让\(a[i]+=a[i-1]\),求最少操作次数使得序列单调不降。
数据范围为\(N \leq 10^6\)
题解
设\(f[i][j]\)表示前\(i\)个数,第\(i\)个数等于\(j - 1\)的最小操作次数。
分\(a[i] = -1 / 0 / 1\)三种情况讨论:(推导转移时记得序列单调不降这个条件)
初始化\(f[i][j] = inf, f[1][a[1]+1] = 0\)。
若\(a[i]=1:\)
\(f[i][0]=f[i-1][0]+2\)
\(f[i][1]=f[i-1][0]+1\)
\(f[i][2]=min(f[i-1][0],min(f[i-1][1],f[i-1][2]))\)
若\(a[i]=0:\)
\(f[i][0]=f[i-1][0]+1\)
\(f[i][1]=min(f[i-1][0],f[i-1][1])\)
\(f[i][2]=f[i-1][2]+1\)
若\(a[i]=-1:\)
\(f[i][0]=f[i-1][0]\)
\(f[i][2]=f[i-1][2]+2\)
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 1e6 + 5;
int n, a[N], f[N][3];
inline int read()
{
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * f;
}
int main ()
{
n = read();
for(int i = 1; i <= n; ++ i) a[i] = read();
memset(f, 0x3f, sizeof(f)); f[1][a[1] + 1] = 0;
for(int i = 2; i <= n; ++ i)
{
if(a[i] == 1)
{
f[i][2] = min(f[i][2], min(f[i - 1][0], min(f[i - 1][1], f[i - 1][2])));
f[i][1] = min(f[i][1], f[i - 1][0] + 1);
f[i][0] = min(f[i][0], f[i - 1][0] + 2);
}
else if(a[i] == 0)
{
f[i][2] = min(f[i][2], f[i - 1][2] + 1);
f[i][1] = min(f[i][1], min(f[i - 1][1], f[i - 1][0]));
f[i][0] = min(f[i][0], f[i - 1][0] + 1);
}
else
{
f[i][2] = min(f[i][2], f[i - 1][2] + 2);
f[i][0] = min(f[i][1], f[i - 1][0]);
}
}
int ans = min(f[n][0], min(f[n][1], f[n][2]));
if(ans == 0x3f3f3f3f) puts("BRAK"); else printf("%d\n", ans);
return 0;
}