HDU 4489 The King’s Ups and Downs (DP+数学计数)

时间:2023-03-10 01:56:17
HDU 4489 The King’s Ups and Downs (DP+数学计数)

题意:给你n个身高高低不同的士兵。问你把他们按照波浪状排列(高低高或低高低)有多少方法数。

析:这是一个DP题是很明显的,因为你暴力的话,一定会超时,应该在第15个时,就过不去了,所以这是一个DP计数问题。

那么我们应该怎么想呢,我们先假设前 i-1 个已经放好了,然后第 i 个一定是最高的,所以,他一定要在前面找一个低后面放上他,肯定不能放在高的后面,

那么状态就有的表示了,d[i][0]表示是以低结尾,d[i][1]是以高结尾,我们假设放第 i 个士兵时,前面有 j 个,那么后面就有 i - j - 1个,前面的乘以后面的,

再乘以 C[i-1][j],就是数量,那么怎么转移呢,就是这样,因为以低结尾和以高结尾,数量肯定是一样,所以,每人都是一半。

那么答案就出来了。再节约一点空间,就可以开成一维的。

代码如下:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <string>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <cstring>
#include <set>
#include <queue>
#include <algorithm>
#include <vector>
#include <map>
#include <cctype>
#include <stack>
using namespace std; typedef long long LL;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const double inf = 0x3f3f3f3f3f3f;
const LL LNF = 100000000000000000;
const double PI = acos(-1.0);
const double eps = 1e-8;
const int maxn = 1e2 + 5;
const int mod = 1e9 + 7;
const char *mark = "+-*";
const int dr[] = {-1, 0, 1, 0};
const int dc[] = {0, 1, 0, -1};
int n, m;
inline bool is_in(int r, int c){
return r >= 0 && r < n && c >= 0 && c < m;
}
inline LL Max(LL a, LL b){ return a < b ? b : a; }
inline LL Min(LL a, LL b){ return a > b ? b : a; }
inline int Max(int a, int b){ return a < b ? b : a; }
inline int Min(int a, int b){ return a > b ? b : a; }
LL C[25][25];
LL d[25]; void init(){
for(int i = 0; i < 25; ++i) C[i][0] = 1;
for(int i = 1; i < 22; ++i)
for(int j = 1; j <= i; ++j)
C[i][j] = C[i-1][j] + C[i-1][j-1]; d[0] = d[1] = 1;
for(int i = 2; i < 21; ++i){
LL ans = 0;
for(int j = 0; j <= i; ++j)
ans += d[j] * d[i-j-1] * C[i-1][j];
d[i] = ans/2;
}
} int main(){
init();
int T; cin >> T;
while(T--){
scanf("%d %d", &m, &n);
printf("%d ", m);
if(1 == n) printf("1\n");
else printf("%I64d\n", d[n]<<1);
}
return 0;
}