题解:AT_dp_t_Permutation

题解:AT_dp_t_Permutation

AT_dp_t_Permutation

分析

一道经典排列 DP,同样的状态设计和转移方程有 2 种不同的理解方法。

#1:具值理解

设计: \(f_{i,j}\) 表示 \(1\sim i\) 的排列,第 \(i\) 位为 \(j\) 的方案数。

边界:\(f_{1,1}=1\)

目标:\(\sum_{k-1}^{n}f_{n,k}\)

转移:考虑算 \(f_{i,j}\),当约束条件为 \(p_{i-1}>p_i\) 时,我们考虑在长为 \(i-1\) 的排列末尾增加一个数 \(j\),但新的序列可能就不是排列了,这时我们只要将原来长 \(i-1\) 的排列中所有 \(\geq j\) 的数 \(+1\) 就可以了。小于约束条件同理

方程:

\(f_{i,j}=\sum_{k=1}^{j-1}f_{i-1,k}\)(“<”)

\(f_{i,j}=\sum_{k=j}^{i-1}f_{i-1,k}\) (“>”)

#2:排名理解

设计: \(f_{i,j}\) 表示 \(1\sim i\) 的排列,第 \(i\) 位在 \(1\sim i\) 的排列中排名为 \(j\) 的方案数。

转移:因为排名是相对的,这时候就不用向上面那种方式一样 \(+1\)

方程:同上

代码

转移方程有很多重复计算,可以使用二维前缀和优化或将转移方程写成递推形式。

//AT_dp_t

#include <iostream>
#include <cstdio>

using namespace std;

typedef long long lld;

const lld mod = 1e9 + 7;
const int N = 3005;

int n;
char st[N];

lld ans, f[N][N];

int main()
{
    scanf("%d %s", &n, st + 2);

    f[1][1] = 1;
    for (int i = 2; i <= n; i ++)
    {
        if (st[i] == '<')
        {
            for (int j = 2; j <= i; j ++)
                f[i][j] = (f[i][j - 1] + f[i - 1][j - 1]) % mod; //递推形式
        }
        else
        {
            for (int j = i - 1; j >= 1; j --)
                f[i][j] = (f[i][j + 1] + f[i - 1][j]) % mod;
        }
    }
    
    for (int i = 1; i <= n; i ++)
        ans = (ans + f[n][i]) % mod;
    
    printf("%lld\n", ans);

    return 0;
}
posted @ 2025-02-04 20:49  nueryim  阅读(36)  评论(0)    收藏  举报