ABC 209 F - Deforestation

F - Deforestation

插入DP,前缀和优化DP

  1. 因为砍一颗树的代价只与相邻的树的高度有关,并且在第 \(i\) 棵与第 \(i+1\) 棵中

    1. 先砍第 \(i\) 棵,代价为 \(h[i-1]+h[i]+h[i+1]+h[i+1]+h[i+2]=h[i-1]+h[i+2]+h[i]+2*h[i+1]\)

    2. 先砍第 \(i+1\) 棵,代价为

      \(h[i]+h[i+1]+h[i+2]+h[i-1]+h[i]=h[i-1]+h[i+2]+2*h[i]+h[i+1]\)

    因此相邻两棵树,先砍较高的那棵是最优的

  2. \(f[i][j]\) 为砍掉前 \(i\) 棵树,且第 \(i\) 棵是第 \(j\) 个砍掉的,得到最小代价的方案数

    1. \(h[i]<h[i+1]\), 先砍第 \(i+1\) 棵,所以第 \(i\) 棵要在第 \([j+1,i+1]\) 次砍,即第 \(i\) 棵要在前 \(i\) 次中的 \([j,i]\) 次砍

      \(f[i+1][j]=\sum\limits_{k=j}^{i}f[i][k]\)

    2. \(h[i]>h[i+1]\), 先砍第 $i $ 棵,所以第 \(i\) 棵要在第 \([1,j-1]\) 次砍,即第 \(i\) 棵要在前 \(i\) 次中的 \([1,j-1]\) 次砍

      \(f[i+1][j]=\sum\limits_{k=1}^{j-1}f[i][k]\)

    3. \(h[i]=h[i+1]\),先砍哪棵都可以

      \(f[i+1][j]=\sum\limits_{k=1}^{i}f[i][k]\)

  3. 前缀和优化 DP

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>

using namespace std;
#define endl "\n"

typedef long long ll;
typedef pair<int, int> PII;

const int N = 4e3 + 10;
const int mod = 1e9 + 7;
int n;
ll f[N][N], sum[N];
ll h[N];
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin >> n;
	for (int i = 1; i <= n; i++)
		cin >> h[i];
	f[1][1] = sum[1] = 1;
	for (int i = 1; i < n; i++)
	{
		for (int j = 1; j <= i + 1; j++)
		{
			if (h[i+1] > h[i])
				f[i+1][j] = (sum[i] - sum[j-1] + mod) % mod;
			else if (h[i+1] < h[i])
				f[i+1][j] = sum[j-1];
			else
				f[i+1][j] = sum[i];
		}
		for (int j = 1; j <= i + 1; j++)
			sum[j] = (sum[j-1] + f[i+1][j]) % mod;
	}
	ll ans = 0;
	for (int i = 1; i <= n; i++)
		ans = (ans + f[n][i]) % mod;
	cout << ans << endl;
    return 0;
}
posted @ 2022-06-08 18:41  hzy0227  阅读(44)  评论(0编辑  收藏  举报