P3558 [POI2013]BAJ-Bytecomputer——线性动归

题意翻译

给一个只包含-1,0,1的数列,每次操作可以让a[i]+=a[i-1],求最少操作次数使得序列单调不降

数据范围为N<=(10^6)

思路

线性dp,(f[i][j])表示进行到第(i)个位置,且让第(i)个位置的值为(j)的最少操作次数

  • 如果(a[i]==-1)

(f[i][-1]=f[i-1][-1])

(f[i][0]=f[i-1][1]+1)不难发现,这种情况是不符合单调递增的条件的,所以不予考虑

(f[i][1]=f[i-1][1]+2)

  • 如果(a[i]==0)

(f[i][-1]=f[i-1][-1]+1)

(f[i][0]=min(f[i-1][0],f[i-1][-1]))

(f[i][1]=f[i-1][1]+1)

  • 如果(a[i]==1)

(f[i][-1]=f[i-1][-1]+2)

(f[i][0]=f[i-1][-1]+1)

(f[i][1]=min(f[i-1][0],f[i-1][1],f[i-1][-1]))

但是下标有负数,怎么办,我们可以加一个偏移量2

就可以解决了

目标状态(min..f[n][0],f[n][1],f[n][-1])

代码

#include<bits/stdc++.h>
using namespace std;
const int base=2;
const int N=1e6+100;
int f[N][4];
int a[N];
int n;
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	memset(f,0x3f,sizeof(f));
	f[1][a[1]+base]=0;
	for(int i=2;i<=n;i++)
	{
		if(a[i]==-1)
		{
			f[i][-1+base]=f[i-1][-1+base];
			// f[i][0+base]=f[i-1][1+base]+1;
			f[i][1+base]=f[i-1][1+base]+2;
		}
		else if(a[i]==0)
		{
			f[i][-1+base]=f[i-1][-1+base]+1;
			f[i][0+base]=min(f[i-1][0+base],f[i-1][-1+base]);
			f[i][1+base]=f[i-1][1+base]+1;
		}
		else if(a[i]==1)
		{
			f[i][-1+base]=f[i-1][-1+base]+2;
			f[i][0+base]=f[i-1][-1+base]+1;
			f[i][1+base]=min(min(f[i-1][0+base],f[i-1][1+base]),f[i-1][-1+base]);
		}
	}
	int ans=min(min(f[n][0+base],f[n][1+base]),f[n][-1+base]);
	if(ans==0x3f3f3f3f) cout<<"BRAK"<<endl;
	else cout<<ans<<endl;
	return 0;
}
原文地址:https://www.cnblogs.com/bangdexuanyuan/p/14063714.html