UVALive 6177 The King’s Ups and Downs

题目链接 http://acm.sdibt.edu.cn/vjudge/ojFiles/uvalive/pdf/61/6177.pdf

题意是  给定一个数n,代表着一共有n个人,且他们的身高从1到n。 要求让这n个人站成一行,使得身高的排列呈波浪形,比如低高低或者高低高。

 

注意:n = 1 ,  ans = 1;

      n = 2 ,  ans = 2;

 

动态规划。

 

解题思路: 每次新加入的点k,可以看成将之前的序列分成前后两部分,并且因为 k是最大的,所以要求k前面数的趋势应该是高低,k后面的趋势应该是底高。这样加入k后的排列数,就是前后可行排列方法数的乘积。 枚举k插入的位置i,以及乘上组合数c(k,i),表示从k个数里面取i个数的取法。

那么怎么计算前后可行排列的方法数呢? 经过推导后,可以证明,前面和后面的方法数是相同的,所以假设用dp[n][0]表示前n个数中以高低为结尾的方法数,dp[n][1]表示前n个数中以底高为开始的方法数,ans[n]表示n个人的时候的方法数,可得 dp[n][0] = dp[n][1] = ans[n] / 2;

dp[i][0]表示i个数中,以高低为结尾的方案数。从n个数里面选i个,每一种组合都可以映射为0,1, ... i。而对于映射后的序列有dp[i][0]种排列,是以高低为结尾。所以插入位置k的前面有dp[i][0] * c(n - 1, i)种可能。又因为为前面选出i个数后,剩下的数就是要放在后面的数,这些数有dp[n - i - 1][1]种以低高开头的排列,所以再乘dp[n-i-1][1]。综上,插入位置k的可能数为dp[i][1] * dp[n-i-1][1] * c(n,i).

 

代码:

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<string.h>
 5 #include<cmath>
 6 #include<algorithm>
 7 #include<queue>
 8 #include<stack>
 9 #include<deque>
10 #include<map>
11 #include<iostream>
12 using namespace std;
13 typedef long long  LL;
14 const double pi=acos(-1.0);
15 const double e=exp(1);
16 const int N = 100009;
17 
18 LL a[25];
19 LL c[25][25];
20 LL sta[25][3],ans[25];
21 
22 void init_c()
23 {
24     LL i,p,j;
25     LL x = 1;
26     for(i = 1; i <= 20; i++)
27     {
28         x *= i;
29         a[i] = x;
30     }
31     a[0] = 1;
32 
33     for(i = 1; i <= 20; i++)
34     {
35         for(j = 0; j <= i; j++)
36         {
37             c[i][j] = a[i] / a[j] / a[i - j];
38         }
39     }
40 }
41 
42 
43 void init_tab()
44 {
45     LL i,p,j;
46 
47     sta[0][0] = sta[0][1] = 1;  //特判 k 插在第一位和最后一位的情况
48     ans[1] = 1;
49     sta[1][0] = sta[1][1] = 1;  //特判 n = 1时,既可以看成是开始为底高的方法数也可以看成是高低的方法数。  
50 
51     for(i = 2; i <= 20; i++)
52     {
53         for(j = 0; j <= i - 1; j++)
54         {
55             ans[i] += sta[j][0] * sta[i - j - 1][1] * c[i - 1][j];
56         }
57         sta[i][0] = sta[i][1] = ans[i] / 2;
58     }
59 }
60 
61 int main()
62 {
63     LL i,p,j,n,t;
64     LL w;
65 
66     init_c();
67     init_tab();
68 
69     scanf("%lld",&t);
70     while(t--)
71     {
72         scanf("%lld%lld",&w,&n);
73         printf("%lld %lld\n",w,ans[n]);
74 
75     }
76     return 0;
77 }
View Code

 

posted @ 2019-03-30 09:03  Daybreaking  阅读(135)  评论(0编辑  收藏  举报