题目翻译
国王有一些身高不同的守卫。他希望给这些守卫安排一个排列,但不是简单地按身高从矮到高或者从高到矮,而是波浪形(每个人总比相邻的两个人都高或都矮),比如:
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
题解
如果令
gi,j=∑nk=j+1gi−1,k
如果算完打个表就知道f和g是对称的(观察一下公式也可以)。
即:
gi,j=fi,i−j+1
就是说,如果原来一个序列为
{ai}
,那么新的序列
{n+1−ai}
的元素仍落在
[1,n]
内,但是相对的大小就与原序列相反。
于是我们有:
又
所以有
也就是说,如果发现一层的dp只与上一层有关,不如考虑一下本层内有没有可以递推的公式。
然后。。结果就是
(因为f表示的是最开始先增的情况,还有对称的最开始先减的情况)
// UVALive 6177, HDU 4489
#include <cstdio>
#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;
}