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;
}
posted @ 2020-04-13 10:36  Sunny_r  阅读(134)  评论(0编辑  收藏  举报