HDU 4489 The King's Ups and Downs

题目链接

问的是n个不一样的数,大小交替,或者小大交替的种类数量。

n个数,想象成[1,n]的自然数即可。

我们假设大小交替得到的长度为i的排列数为dp1[i],小大交替得到的长度为i的排列数为dp2[i],因为是对称的,其实应该有dp1=dp2,我们要计算的总和sum=dp1+dp2。

我们从小到大考虑各个数,一个个插入队列,考虑到第i个数,称为ai,ai比前i-1个数都大,可以插入的位置j∈[1,i]。

ai前面有i-1个人比自己小,ai选择站在j的位置,在i-1个人中选j-1个人站在ai的前面,排列的情况有C(i-1,j-1)。插入第j个位置,ai属于“高”,要求ai前面和ai衔接的情况是低高,ai和后面一个衔接的情况是高低。所以插入j位置时候的排列数有 dp1[j-1] * dp2[i - j] * c[i-1][j-1]种。

#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define mst(a,b) memset(a,b,sizeof(a))
#define rep(i,a,b) for(ll i=(a);i<(b);++i)
const int inf = 0x3f3f3f3f, maxN = 25 + 5;
int N, M, T;

ll dp1[maxN];
ll dp2[maxN];
ll sum[maxN];
ll c[maxN][maxN];

ll cal(int n, int m) {
    c[1][0] = c[1][1] = 1;
    rep(i, 2, n) {
        c[i][0] = 1;
        rep(j, 1, n)
            c[i][j] = c[i - 1][j] + c[i - 1][j - 1];
    }
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("data.in", "r", stdin);
#endif
    cal(20, 20);
    dp1[0] = dp1[1] = dp2[0] = dp2[1] = 1;
    sum[1] = 1;
    rep(i, 2, 20 + 1) {
        sum[i] = 0;
        rep(j, 1, i + 1)
            sum[i] += (dp1[j - 1] * dp2[i - j] * c[i - 1][j - 1]);
        dp1[i] = dp2[i] = sum[i] / 2;
    }
    scanf("%d", &T);
    rep(i, 1, T + 1) {
        scanf("%d%d", &M, &N);
        printf("%d %lld
", M, sum[N]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Rosebud/p/9077030.html