codeforces Make The Fence Great Again(dp)

题目链接:http://codeforces.com/contest/1221/problem/D

题目要求ai ! = ai-1,草纸上推理一下可以发现每一个栅栏可以升高的高度无非就是 +0,+1,+2

用dp【i】【j】表示到第 i 个栅栏升高 j 高度时,所需要的最小花费。

状态转移方程:dp[i][j] = min(dp[i-1][k]+j*b[i],dp[i][j]),其实每次循环共枚举了9次,分别是第 i 个栅栏升高 j 高度时候,对前一个也就是第i-1个栅栏分别升高+0,+1,+2高度的枚举,最终取一个min(枚举出第 i 个升高 j 高度满足ai!= ai-1的最小花费),一共是9次。

AC代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<set>
#include<map>
#define inf 0x3f3f3f3f
using namespace std;
int main(){
    ios::sync_with_stdio(false);
	int q;
	scanf("%d",&q);
	while(q--){
		long long int dp[300001][3];
		long long int a[300001],b[300001];
		int n;
		scanf("%d",&n);
		for(int i = 0;i<n;i++){
			scanf("%lld%lld",&a[i],&b[i]);
			dp[i][0] = 1e18,dp[i][1] = 1e18,dp[i][2] = 1e18;
		}
		dp[0][0] = 0,dp[0][1] = b[0],dp[0][2] = 2*b[0];
		for(int i = 1;i<n;i++){
			for(int j = 0;j<3;j++){
				for(int k = 0;k<3;k++){
					if((a[i]+j) == (a[i-1]+k)){
						continue;//如果ai == ai-1跳出循环 
					}
					dp[i][j] = min(dp[i-1][k]+j*b[i],dp[i][j]);
				}
			}
		}
		printf("%lld
",min(dp[n-1][0],min(dp[n-1][1],dp[n-1][2])));
	}
	return 0;
}
原文地址:https://www.cnblogs.com/AaronChang/p/12129626.html