https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4188
国王有一些身高不同的守卫。他希望给这些守卫安排一个排列,但不是简单地按身高从矮到高或者从高到矮,而是波浪形(每个人总比相邻的两个人都高或都矮),比如:
160, 162, 164, 166, 168, 170, 172
的两种可行排列是:
160, 164, 162, 168, 166, 172, 170
或者
172, 160, 170, 162, 168, 164, 166
。
国王希望知道有多少种排列方式。为了方便表示,我们按 1,2,⋯ 表示身高从矮到高。
如果有4个守卫,那么有一下几种排列:
1324, 2143, 3142, 2314, 3412, 4231, 4132, 2413, 3241, 1423
计算有n个守卫时的排列方式有多少种。
第一行一个整数 P(1≤P≤1000) ,表示数据组数。接下来每组数据一行2个整数 D,n(1≤n≤20) ,分别表示数据组编号和守卫的个数(身高总不相同)。
对于每组数据输出一行2个整数 D 和排列数。
4
1 1
2 3
3 4
4 20
1 l
2 4
3 10
4 740742376475050
如果令 fi,j 表示排列的第 i 位为 j ,且 i−1 位的数字小于 j (我们只关心数字的相对大小), gi,j 表示排列的第 i 位为 j ,且 i−1 位的数字大于 j 。那么显然有:
fi,j=∑j−1k=1fi−1,k
gi,j=∑nk=j+1gi−1,k
如果算完打个表就知道f和g是对称的(观察一下公式也可以)。
即: gi,j=fi,i−j+1
就是说,如果原来一个序列为 {ai} ,那么新的序列 {n+1−ai} 的元素仍落在 [1,n] 内,但是相对的大小就与原序列相反。
于是我们有:
// UVALive 6177, HDU 4489
#include
#define FOR(i,j,k) for(i=j;i<=k;++i)
const int N = 21;
long long dp[N][N], ans[N];
int main() {
int T, kase, n, i, j;
dp[1][1] = 1;
ans[1] = 1;
FOR(i,2,20) FOR(j,2,i) {
dp[i][j] = dp[i - 1][i - j + 1] + dp[i][j - 1];
ans[i] += dp[i][j] * 2;
}
scanf("%d", &T);
while (T--) {
scanf("%d%d", &kase, &n);
printf("%d %lld\n", kase, ans[n]);
}
return 0;
}