题解: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;
}

浙公网安备 33010602011771号