LINK

题意

n n n棵树,砍掉第 i i i棵树的代价是 H i + H i − 1 + H i + 1 H_i+H_{i-1}+H_{i+1} Hi+Hi1+Hi+1,之后 H i H_i Hi变为 0 0 0

砍掉这 n n n课树有 n ! n! n!种砍树顺序,问有多少种是最小代价的砍树方案.


怎样砍树是最优的?

现在只考虑第 i i i棵树和第 i + 1 i+1 i+1棵树带来的代价

若第 i i i棵树先被砍,那么此时代价为 H i + 2 ∗ H i + 1 H_i+2*H_{i+1} Hi+2Hi+1

若第 i + 1 i+1 i+1棵树先被砍,那么此时代价为 2 ∗ H i + H i + 1 2*H_i+H_{i+1} 2Hi+Hi+1

得到结论若 H i < H i + 1 H_i<H_{i+1} Hi<Hi+1,先砍第 i + 1 i+1 i+1棵树

H i > H i + 1 H_i>H_{i+1} Hi>Hi+1,先砍第 i i i棵树

定义 f [ i ] [ j ] f[i][j] f[i][j]表示前 i i i个棵树中第 i i i棵是第 j j j次被砍掉的最小代价

H i < H i + 1 H_i<H_{i+1} Hi<Hi+1,意味着 i + 1 i+1 i+1位置需要先放,有转移

f [ i + 1 ] [ j ] = ∑ k = j i f [ i ] [ k ] f[i+1][j]=\sum\limits_{k=j}^i f[i][k] f[i+1][j]=k=jif[i][k]

H i > H i + 1 H_i>H_{i+1} Hi>Hi+1,意味着 i i i位置需要先放,有转移

f [ i + 1 ] [ j ] = ∑ k = 1 j − 1 f [ i ] [ k ] f[i+1][j]=\sum\limits_{k=1}^{j-1} f[i][k] f[i+1][j]=k=1j1f[i][k]

H i = H i + 1 H_i=H_{i+1} Hi=Hi+1,什么先后顺序都无所谓,有转移

f [ i + 1 ] [ j ] = ∑ k = 1 i f [ i ] [ k ] f[i+1][j]=\sum\limits_{k=1}^{i} f[i][k] f[i+1][j]=k=1if[i][k]

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e9+7; 
const int maxn = 5009;
int n,h[maxn],f[maxn][maxn],sum[maxn];
signed main()
{
	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;
			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;
	}
	int ans = 0;
	for(int i=1;i<=n;i++)	ans = ( ans+f[n][i] )%mod;
	cout << ( ans%mod+mod )%mod;
	return 0;
}