HDU 4055 The King’s Ups and Downs(DP计数)

题意:国王的士兵有n个,每个人的身高都不同,国王要将他们排列,必须一高一矮间隔进行,即其中的一个人必须同时高于(或低于)左边和右边。问可能的排列数。例子有1千个,但是最多只算到20个士兵,并且20个的情况的答案已给出。

思路:是此题HDU 4055 Number String(DP计数) 的简单版,所以看此题解就行了。数量较小,可以预先算出来。要同时考虑 <><>和><><这样的两种情况。

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <stdlib.h>
 5 using namespace std;
 6 const int N=23;
 7 long long dp1[N][N];
 8 long long dp2[N][N];
 9 long long ans[N];
10 int j, n;
11 int cal()
12 {
13     ans[1]=1;
14     dp1[0][1]=dp2[0][1]=1;
15     for(int i=1; i<N; i++)
16     {
17         if(i&1)     //大于
18         {
19             for(int j=1; j<=i+1; j++)
20             {
21                 dp1[i][j]=dp1[i][j-1];
22                 dp1[i][j]+=dp1[i-1][j-1];
23                 ans[i+1]+=dp1[i][j];
24             }
25         }
26         else
27         {
28             for(int j=i+1; j>0; j--)
29             {
30                 dp1[i][j]=dp1[i][j+1];
31                 dp1[i][j]+=dp1[i-1][j];
32                 ans[i+1]+=dp1[i][j];
33             }
34         }
35     }
36
37     for(int i=1; i<N; i++)
38     {
39         if(i&1)     //大于
40         {
41             for(int j=i+1; j>0; j--)
42             {
43                 dp2[i][j]=dp2[i][j+1];
44                 dp2[i][j]+=dp2[i-1][j];
45                 ans[i+1]+=dp2[i][j];
46             }
47         }
48         else
49         {
50             for(int j=1; j<=i+1; j++)
51             {
52                 dp2[i][j]=dp2[i][j-1];
53                 dp2[i][j]+=dp2[i-1][j-1];
54                 ans[i+1]+=dp2[i][j];
55             }
56         }
57     }
58     return 0;
59 }
60 int main()
61 {
62     //freopen("input.txt","r",stdin);
63     cal();
64     int p;
65     cin>>p;
66     while(p--)
67     {
68         scanf("%d%d",&j,&n);
69         cout<<j<<" "<<ans[n]<<endl;
70     }
71     return 0;
72 }

易理解版本

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <stdlib.h>
 5 using namespace std;
 6 const int N=21;
 7 long long dp[N][N],ans[N];
 8 int j, n;
 9 void cal()
10 {
11     ans[1]=1;
12     for(int k=0; k<2; k++)
13     {
14         dp[0][1]=1;
15         for(int i=1; i<N; i++)
16         {
17             if((i+k)&1)     //大于
18             {
19                 for(int j=1; j<=i+1; j++)
20                 {
21                     dp[i][j]=dp[i][j-1];
22                     dp[i][j]+=dp[i-1][j-1];
23                     ans[i+1]+=dp[i][j];
24                 }
25             }
26             else
27             {
28                 for(int j=i+1; j>0; j--)
29                 {
30                     dp[i][j]=dp[i][j+1];
31                     dp[i][j]+=dp[i-1][j];
32                     ans[i+1]+=dp[i][j];
33                 }
34             }
35         }
36         memset(dp,0,sizeof(dp) );
37     }
38 }
39 int main()
40 {
41     //freopen("input.txt","r",stdin);
42     cal();
43     int p;cin>>p;
44     while(p--)
45     {
46         scanf("%d%d",&j,&n);
47         cout<<j<<" "<<ans[n]<<endl;
48     }
49     return 0;
50 }

节省一半空间和代码量的版本

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <stdlib.h>
 5 using namespace std;
 6 const int N=21;
 7 long long dp[2][N],ans[N];
 8 int j, n;
 9 void cal()
10 {
11     ans[1]=1;
12     for(int k=0; k<2; k++)
13     {
14         dp[0][1]=1;
15         for(int i=1; i<N; i++)
16         {
17             if((i+k)&1)     //大于
18             {
19                 for(int j=1; j<=i+1; j++)
20                 {
21                     dp[i&1][j]=dp[i&1][j-1];
22                     dp[i&1][j]+=dp[~i&1][j-1];
23                     ans[i+1]+=dp[i&1][j];
24                 }
25             }
26             else
27             {
28                 for(int j=i+1; j>0; j--)
29                 {
30                     dp[i&1][j]=dp[i&1][j+1];
31                     dp[i&1][j]+=dp[~i&1][j];
32                     ans[i+1]+=dp[i&1][j];
33                 }
34             }
35         }
36         memset(dp,0,sizeof(dp) );
37     }
38 }
39 int main()
40 {
41     //freopen("input.txt","r",stdin);
42     cal();
43     int p;cin>>p;
44     while(p--)
45     {
46         scanf("%d%d",&j,&n);
47         cout<<j<<" "<<ans[n]<<endl;
48     }
49     return 0;
50 }

滚动数组版本(更少空间)

时间: 2024-10-16 20:09:17

HDU 4055 The King’s Ups and Downs(DP计数)的相关文章

HDU 4489 The King&#39;s Ups and Downs

题目链接 问的是n个不一样的数,大小交替,或者小大交替的种类数量. n个数,想象成[1,n]的自然数即可. 我们假设大小交替得到的长度为i的排列数为dp1[i],小大交替得到的长度为i的排列数为dp2[i],因为是对称的,其实应该有dp1=dp2,我们要计算的总和sum=dp1+dp2. 我们从小到大考虑各个数,一个个插入队列,考虑到第i个数,称为ai,ai比前i-1个数都大,可以插入的位置j∈[1,i]. ai插入的位置为j时,前面的i-1个人比自己小,选择出来排列的情况有C(i-1,j-1)

UVA 6177 The King&#39;s Ups and Downs DP

orz想了好久好久的排列组合,未果,考虑不全--DP好难啊233333 题目链接戳这里 抛开整体不考虑,我们来考虑一下只有3个人的局部问题: 只要第i-1个人比i矮(高)第i+1个人比i矮(高),i当前位置就是满足题意的 设f[i][j]为排列的第i位为j,而且i-1位比j小 设g[i][j]为排列的第i位位j,而且i-1位比j大 emmmmm明天补 #include<bits/stdc++.h> using namespace std; typedef long long ll; const

HDU 4489 The King’s Ups and Downs

http://acm.hdu.edu.cn/showproblem.php?pid=4489 题意:有n个身高不同的人,计算高低或低高交错排列的方法数. 思路:可以按照身高顺序依次插进去. d[i][0]表示i个人以高低结尾的方法数,d[i][1]表示i个人以低高开头的方法数. 将第i个人插入时,当它左边为j个人的时候,右边就是i-1-j,并且左边必须要以高低结尾,右边必须以低高开头.也就是d[i-1][0]*d[i-1][1].当然了,后面还得再乘c(i-1,j),表示选j个人的方法数. 1

HDU 4489 The King’s Ups and Downs (DP+数学计数)

题意:给你n个身高高低不同的士兵.问你把他们按照波浪状排列(高低高或低高低)有多少方法数. 析:这是一个DP题是很明显的,因为你暴力的话,一定会超时,应该在第15个时,就过不去了,所以这是一个DP计数问题. 那么我们应该怎么想呢,我们先假设前 i-1 个已经放好了,然后第 i 个一定是最高的,所以,他一定要在前面找一个低后面放上他,肯定不能放在高的后面, 那么状态就有的表示了,d[i][0]表示是以低结尾,d[i][1]是以高结尾,我们假设放第 i 个士兵时,前面有 j 个,那么后面就有 i -

DpUVALive 6177The King&#39;s Ups and Downs

练习赛的时候写了个爆搜,然后没跑出来 就不搞了, 田腿说用状压跑,打表.其实有能直接过的Dp吧. 下面是打表的Dp..结果除了第一个 其余乘以2就行了. #include <cstdio> #include <cstring> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #inclu

The King’s Ups and Downs

有n个高矮不同的士兵,现在要将他们按高,矮依次排列,问有多少种情况. 化简为 n个人,求出可以形成波浪形状的方法数 #include <iostream> #include <cmath> #include <math.h> #include <vector> #include <cstdio> #include <cstring> #include <algorithm> #define ll long long usi

hdu 3861 The King’s Problem (强连通+最小路径覆盖)

The King's Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 1637    Accepted Submission(s): 600 Problem Description In the Kingdom of Silence, the king has a new problem. There are N cit

HDU 3861 The King’s Problem(强连通+二分图最小路径覆盖)

HDU 3861 The King's Problem 题目链接 题意:给定一个有向图,求最少划分成几个部分满足下面条件 互相可达的点必须分到一个集合 一个对点(u, v)必须至少有u可达v或者v可达u 一个点只能分到一个集合 思路:先强连通缩点,然后二分图匹配求最小路径覆盖 代码: #include <cstdio> #include <cstring> #include <vector> #include <algorithm> #include <

ZOJ 2334 HDU 1512 Monkey King

题意: 猴子们打架  认识的猴子不会打架  两只猴子打完以后就认识了  A认识B B认识C A也认识C  每次打架由两伙猴子进行  分别选出自己的最高战斗力  在战斗之后两只猴子战斗力减半  给出m次打架  输出打架后这一伙猴子里的最强战斗力 思路: 判断两只猴子是不是一伙的  用到并查集 快速找出一伙猴子中的最强战斗力用到堆  但打完架两伙猴子合并时堆需要nlogn复杂度  因此用左偏树代替堆 代码: #include<cstdio> #include<cstring> #inc