The King’s Ups and Downs (线性DP)
[link](Problem - 4489 (dingbacode.com))
题意
给你n个身高不同的人,问你这些人按照波浪形排列有多少种情况?
波浪形类似于 /
题解
首先要想一种方式可以不重不漏的把所有的方案包含住。这里假设 n n n个人的身高是 [ 1 , n ] [1, n] [1,n],我们从前往后枚举每一个人,假设当前到了第 i i i个人,第 i i i个人前面有 i − 1 i-1 i−1个人,所以第 i i i个人有 i i i个位置可以放置。假设当前要插在第 j j j个位置,那么他一定要满足第 j − 1 j-1 j−1个人是以下降过来的(类似于),第 n − j n-j n−j个人是以上升到第 n − j + 1 n-j+1 n−j+1个人的。
那么插到第 j j j个位置的贡献就是
有 j − 1 个 人 且 最 后 是 下 降 的 情 况 × 有 n − j 个 人 且 开 始 是 上 升 的 情 况 × C i − 1 j − 1 ( 前 j − 1 个 数 是 谁 ) 有j-1个人且最后是下降的情况 \times 有n-j个人且开始是上升的情况 \times C_{i-1}^{j -1}(前j-1个数是谁) 有j−1个人且最后是下降的情况×有n−j个人且开始是上升的情况×Ci−1j−1(前j−1个数是谁)。
因此状态表示为
sum[i]:i个人的合法情况
f[i, 0]:i个人并且最后是下降的合法情况f[i, 1]:i个人并且开始时上升的合法情况
状态转移
sum[i]由前面每一个合法位置的贡献累加起来
每一次的sum[i]的结尾一定是上升或下降过来的,所以f[i, 0] = f[i, 1] = sum[i] / 2
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <bitset>
#include <unordered_map>
#include <cmath>
#include <stack>
#include <iomanip>
#include <deque>
#include <sstream>
#define x first
#define y second
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
LL c[21][21];
LL sum[21];
LL f[21][2]; // f[i][0] 最后一个下降, f[i][1] 第一个上升得到下一个
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T;
for (int i = 0; i <= 20; i ++ )
for (int j = 0; j <= i; j ++ )
if (j) c[i][j] = c[i - 1][j] + c[i - 1][j - 1];
else c[i][j] = 1;
f[0][0] = f[0][1] = f[1][0] = f[1][1] = 1;
sum[1] = 1;
for (int i = 2; i <= 20; i ++ ) {
for (int j = 1; j <= i; j ++ )
sum[i] += f[j - 1][0] * f[i - j][1] * c[i - 1][j - 1];
f[i][0] = f[i][1] = sum[i] / 2;
}
cin >> T;
while (T -- ) {
cin >> n >> k;
cout << n << ' ' << sum[k] << endl;
}
return 0;
}