The King’s Ups and Downs (线性DP)

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 i1个人,所以第 i i i个人有 i i i个位置可以放置。假设当前要插在第 j j j个位置,那么他一定要满足第 j − 1 j-1 j1个人是以下降过来的(类似于),第 n − j n-j nj个人是以上升到第 n − j + 1 n-j+1 nj+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个数是谁) j1×nj×Ci1j1j1

因此状态表示为

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;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值