P3558 BAJ-Bytecomputer
P3558 BAJ-Bytecomputer
题意:
给定一个长度为 \(n\) 的只包含 \(-1,0,1\) 的数列 \(a\) ,每次操作可以使 \(a_i \leftarrow a_i + a_{I - 1}\) ,求最少操作次数使得序列单调不降。如果不可能通过改操作使得序列不下降,输出 BRAK
思路:
每个位置一共有三种可能,很明显的动态规划问题,定义 \(f[i][j]\) 为遍历到第 \(i\) 个点,当前数值为 \(j\) 时需要的最少花费。
剩下的参考:https://www.luogu.com.cn/blog/NKU-AI/solution-p3558
实现:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5, INF = 1e9;
int f[N][4];
int a[N];
int main()
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for (int i = 0; i <= n; i++)
for (int j = 0; j < 4; j++)
f[i][j] = INF;
f[1][a[1] + 1] = 0;
for (int i = 2; i <= n; i++)
{
if (a[i] == -1)
{
// 当前为 -1 的话,前面的最大值也为 -1 时直接转移
f[i][0] = f[i - 1][0];
// 没必要让当前变成0,增加了负担又不能为后面贡献1
// 变成 1 的话,需要前一个是 1 ,并且操作 2 次
f[i][2] = f[i - 1][2] + 2;
}
else if (a[i] == 0)
{
// 当前变成 -1 的话,需要前一个是 -1 然后操作一次
f[i][0] = f[i - 1][0] + 1;
// 当前保持 0 的话,前面可以是 -1 或者 0
f[i][1] = min(f[i - 1][1], f[i - 1][0]);
// 当前变 1 需要前面是1并且操作一次
f[i][2] = f[i - 1][2] + 1;
}
else if (a[i] == 1)
{
// 变成 -1
f[i][0] = f[i - 1][0] + 2;
// 变成 0
f[i][1] = f[i - 1][0] + 1;
// 变成 1
f[i][2] = min({f[i - 1][0], f[i - 1][1], f[i - 1][2]});
}
}
int res = min({f[n][0], f[n][1], f[n][2]});
if (res >= INF)
printf("BRAK\n");
else
printf("%d\n", res);
return 0;
}