题目链接 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;
代码:
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 ",w,ans[n]); 74 75 } 76 return 0; 77 }