UVALive 6177|HDU 4489|The King's Ups and Downs|动态规划

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(1P1000) ,表示数据组数。接下来每组数据一行2个整数 D,n(1n20) ,分别表示数据组编号和守卫的个数(身高总不相同)。

输出

对于每组数据输出一行2个整数 D 和排列数。

样例输入

4
1 1
2 3
3 4
4 20

样例输出

1 l
2 4
3 10
4 740742376475050

题解

如果令 fi,j 表示排列的第 i 位为 j ,且 i1 位的数字小于 j (我们只关心数字的相对大小), gi,j 表示排列的第 i 位为 j ,且 i1 位的数字大于 j 。那么显然有:
fi,j=j1k=1fi1,k
gi,j=nk=j+1gi1,k
如果算完打个表就知道f和g是对称的(观察一下公式也可以)。
即: gi,j=fi,ij+1
就是说,如果原来一个序列为 {ai} ,那么新的序列 {n+1ai} 的元素仍落在 [1,n] 内,但是相对的大小就与原序列相反。
于是我们有:

fi,j=k=1j1fi1,ik


fi,j1=k=1j2fi1,ik

所以有
fi,j=fi,j1+fi1,ij+1

也就是说,如果发现一层的dp只与上一层有关,不如考虑一下本层内有没有可以递推的公式。
然后。。结果就是
ansn=2ifn,i

(因为f表示的是最开始先增的情况,还有对称的最开始先减的情况)

// 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;
}

你可能感兴趣的:(UVa,HDU,——动态规划——)