ATCODER ABC209F Deforestation 基础题解

分析

状态定义:\(dp[i][j] | (j \le i)\)表示前\(i\)棵树中,第\(i\)棵树是第\(j\)棵被砍的排列的方案数。

状态转移:根据讨论,如果\(H_i > H_{i+1}\),则先砍\(H_i\)。如果\(H_i < H_{i+1}\),则先砍\(H_{i+1}\)。如果\(H_i = H_{i+1}\),则先砍这两棵树都可以。总之,谁高就先砍谁。

if(H[i] > H[i+1]) \(dp[i+1][j] = \sum_{k=1}^{j-1} dp[i][k]\),就是第\(i\)棵树只要在第\(i+1\)棵树之前的任何一个位置被砍都是合法的排列方案。

if(H[i] < H[i+1]) \(dp[i+1][j] = \sum_{k=j}^{i}dp[i][k]\) , 就是第\(i\)棵树只能在位置\(j-i\)被砍。这是有一个比较特殊的地方,就是第\(i\)棵树似乎应该在位置\(j+1\)及之后被砍。为什么位置\(j\)也可以呢?

我的理解是:对于第\(i\)棵树是在位置\(j\)被砍的排列,把第\(i+1\)棵树强行安排在位置\(j\)去砍,相当于第\(i\)棵树及后面的树都后移一个位置,得到的排列仍然合法。

if(H[i] == H[i+1]) \(dp[i+1][j] = \sum_{k=1}^i dp[i][k]\), 就是第\(i\)棵树的被砍位置不影响第\(i+1\)棵树的位置。

TLE 代码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 4005
#define MOD (int)(1E9+7)
int h[MAXN];
int dp[MAXN][MAXN];
int n, ans;
int main(){
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> h[i];
    dp[1][1] = 1;
    for(int i = 1; i < n; i++){
        for(int j = 1; j <= i+1; j++)
            if(h[i] == h[i+1])
                for(int k = 1; k <= i; k++)
                    dp[i+1][j] += dp[i][k], dp[i+1][j] %= MOD;
            else if(h[i] > h[i+1])
                for(int k = 1; k <= j-1; k++)
                    dp[i+1][j] += dp[i][k], dp[i+1][j] %= MOD;
            else 
                for(int k = j; k <= i; k++)
                    dp[i+1][j] += dp[i][k], dp[i+1][j] %= MOD;
    }
    for(int j = 1; j <= n; j++) {
        ans += dp[n][j];
        ans %= MOD;
    }
    cout << ans << endl;
}

AC代码,空间未优化

#include<bits/stdc++.h>
using namespace std;
#define MAXN 4005
#define MOD (int)(1E9+7)
int h[MAXN];
long long dp[MAXN][MAXN], sum[MAXN][MAXN];
int n, ans;
int main(){
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> h[i];
    dp[1][1] = sum[1][1] = 1;
    for(int i = 1; i < n; i++)
        for(int j = 1; j <= i+1; j++) {
            if(h[i] == h[i+1])
                dp[i+1][j] += sum[i][i], dp[i+1][j] %= MOD;
            else if(h[i] > h[i+1])
                dp[i+1][j] += sum[i][j-1], dp[i+1][j] %= MOD;
            else {
                dp[i+1][j] += sum[i][i] - sum[i][j-1], dp[i+1][j] %= MOD;
                if(dp[i+1][j] < 0) dp[i+1][j] += MOD;
            }
            sum[i+1][j] += (sum[i+1][j-1] + dp[i+1][j]) % MOD;
        }
    for(int j = 1; j <= n; j++) {
        ans += dp[n][j];
        ans %= MOD;
    }
    cout << ans << endl;
}

ATCODER ABC209F Deforestation 基础题解

上一篇:C#获取CPU和内存使用率


下一篇:ambari重装失败的排错思路例子:重装Log Search遇到的重装失败