HDU 6114 Chess(DP)2017百度之星初赛(B) 1001
2017-08-13 17:39
218 查看
题意:
对于任何一个車A,如果有其他一个車B在它的上方(車B行号小于車A),那么車A必须在車B的右边(車A列号大于車B)。在满足该条件的情况下,摆最多棋子的 方案数有多少。
思路:
自底向上来思考,用n表示行数,m表示列数。先假设一种极端情况(n<m),先摆好前n-1行,如下图。
n:3 m:5(1表示已经放了一个棋子,0表示不放旗子,2表示可以选择放旗子)
设第n-1行摆放棋子为j列。
通过上图可以分析出来,这种情况下,摆放方案有m-j种。
再看另一种情况。
显然上述的结论也是成立的,那我们怎么通过最后一行推出前面行的情况呢?
我们先做一个处理,将每个点所处的该行的右边放棋子的方案数都加到自身上,即dp[i][j]+=dp[i][j+1…n](j>=i)
注意!!下面图中的数字为以该点为 左上顶点做棋盘的边界 的所有方案数。而不是表示之前放旗子的状态
什么意思呢?就比如该点为(i,j)时,以n-i+1为行数,m-j+1为列数做棋盘的所有方案数。
先从最后一行开始。(前面的n-1行还未处理所以都为0)
当j<i时,不可能有放棋子的可能,因为要求所放的棋子数最大!这点应该很好想。
处理完最后一行,我们怎么把数目转移到n-1行上呢?
其实通过之前的观察我们就知道,如果我们确定一个点要放棋子,那这种情况下,所有的方案数就等于dp[i+1][j+1]。即取决于它右下角的那个位置的方案数。
dp的状态转移公式:
dp[i][j]+=dp[i+1][j+1]+dp[i][j+1]; (i+1<=n && j+1<=m)
我们继续处理完吧✧(≖ ◡ ≖✿),不理解的话,再看看下面的图,或许会比较好理解。
✨✨最后dp[1][1]就是我们要求的答案啦~
附上代码~
对于任何一个車A,如果有其他一个車B在它的上方(車B行号小于車A),那么車A必须在車B的右边(車A列号大于車B)。在满足该条件的情况下,摆最多棋子的 方案数有多少。
思路:
自底向上来思考,用n表示行数,m表示列数。先假设一种极端情况(n<m),先摆好前n-1行,如下图。
n:3 m:5(1表示已经放了一个棋子,0表示不放旗子,2表示可以选择放旗子)
1 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 0 | 0 |
0 | 0 | 2 | 2 | 2 |
通过上图可以分析出来,这种情况下,摆放方案有m-j种。
再看另一种情况。
1 | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 0 | 0 |
0 | 0 | 0 | 2 | 2 |
我们先做一个处理,将每个点所处的该行的右边放棋子的方案数都加到自身上,即dp[i][j]+=dp[i][j+1…n](j>=i)
注意!!下面图中的数字为以该点为 左上顶点做棋盘的边界 的所有方案数。而不是表示之前放旗子的状态
什么意思呢?就比如该点为(i,j)时,以n-i+1为行数,m-j+1为列数做棋盘的所有方案数。
先从最后一行开始。(前面的n-1行还未处理所以都为0)
0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
0 | 0 | 3 | 2 | 1 |
处理完最后一行,我们怎么把数目转移到n-1行上呢?
其实通过之前的观察我们就知道,如果我们确定一个点要放棋子,那这种情况下,所有的方案数就等于dp[i+1][j+1]。即取决于它右下角的那个位置的方案数。
dp的状态转移公式:
dp[i][j]+=dp[i+1][j+1]+dp[i][j+1]; (i+1<=n && j+1<=m)
我们继续处理完吧✧(≖ ◡ ≖✿),不理解的话,再看看下面的图,或许会比较好理解。
0 | 0 | 0 | 0 | 0 |
0 | 6 | 3 | 1 | 0 |
0 | 0 | 3 | 2 | 1 |
10 | 4 | 1 | 0 | 0 |
0 | 6 | 3 | 1 | 0 |
0 | 0 | 3 | 2 | 1 |
附上代码~
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int M=1e9+7; typedef long long ll; int n,m; ll dp[1005][1005]; int main(){ int t; int nt,mt; scanf("%d",&t); while(t--){ scanf("%d%d",&nt,&mt); n=min(nt,mt);//为了方便处理,都让行数<=列数 m=max(nt,mt); memset(dp,0, sizeof(dp)); for (int j = m; j >=n ; --j) { dp [j]=1; } for (int i = n; i >=1; --i) { for (int j = m; j >=i ; --j) { if(j+1<=m && i+1<=n) dp[i][j]=(dp[i][j]+dp[i+1][j+1])%M; if(j+1<=m) dp[i][j]=(dp[i][j]+dp[i][j+1])%M; } } printf("%I64d\n",dp[1][1]); } return 0; }
相关文章推荐
- 【2017百度之星】HDU 6114 Chess 【组合数取模,Lucas定理】
- 2018.3.1【 HDU - 6114 】解题报告(百度之星初赛,简单dp,组合数)
- 2017百度之星初赛(B) 1001 Chess(思维+Lucas)
- HDU-2017"百度之星"程序设计大赛-初赛(B)-1001-Chess
- 2017百度之星初赛(B) 1001 Chess(找规律+递推求组合数)
- HDU 6114 Chess 【组合数】(2017"百度之星"程序设计大赛 - 初赛(B))
- HDU 6114 Chess 【组合数】(2017"百度之星"程序设计大赛 - 初赛(B))
- HDU 6108 2017 百度之星 初赛A 1001 小C的倍数问题
- hdu 6119/2017百度之星初赛B——小小粉丝度度熊(尺取/贪心)
- 2017百度之星初赛B-1002(HDU-6115)
- 百度之星2017初赛A轮 1001 小C的倍数问题
- 2017"百度之星"程序设计大赛 - 初赛(B) 1001 Chess
- 2016"百度之星" - 初赛(Astar Round2A)1002 / HDU 5691 状态压缩DP
- HDU 6108 小C的倍数问题 (数论 2017百度之星初赛A第1题)
- 2017"百度之星"程序设计大赛 - 初赛(A)1001——HDU 6108【求因子数】【思维题】
- 2017百度之星初赛:A-1001. 小C的倍数问题
- 2017百度之星初赛A-1006(HDU-6113)
- hdu 4833 Best Financing(百度之星初赛,DAG上dp,离散化)
- 百度之星 2017初赛第一场 1001 小C的倍数问题
- HDU 6112 今夕何夕 (日历题 Zeller公式 2017百度之星初赛A第五题)