2020第十一届蓝桥杯7月省赛E题
试题E:矩阵
题目描述:
本题思路:
这道题如果暴力跑,2020层递归调用(爆栈先不说,我们学校的电脑绝对要先死机)
这道题我用dp写的(嘿嘿,在这里感谢一下yzzz)。
首先,我们初读题目可以发现:第一排的最左边一定是1,第二排的最右边一定是2020。因为要求右边比左边大,下面比上面大,那么我们可以得知第一排一定是升序排列,第二排也一定是升序排列,那么我们只要顺序遍历其实就是可以满足升序的要求的,现在需要解决的就是同一列上下面的数大于上面的数的要求。
因为2020这个数字比较大,我们不妨先模拟一下较小的数字。我们模拟n = 6的场景:一共有五种方案
case1:
1 | 2 | 3 |
---|---|---|
4 | 5 | 6 |
case2:
1 | 2 | 4 |
---|---|---|
3 | 5 | 6 |
case3:
1 | 3 | 4 |
---|---|---|
2 | 5 | 6 |
case4:
1 | 3 | 5 |
---|---|---|
2 | 4 | 6 |
case5:
1 | 2 | 5 |
---|---|---|
3 | 4 | 6 |
我们模拟上面的式子过程中,很容易发现以下特性:
在顺序模拟过程中,我们可以无条件的在第一行填写数字;
第二行填写数字的要求是:只有当同一列的第一行有数字时我们才可以进行填写。(这样子可以满足同一列中第二行的数字比第一行的数字大的要求,原因是我们是顺序遍历的,后面的数字肯定比前面的数字大)
所以我们用dp[i][j]表示第一排放i个数,第二排放j个数时的方案数。
状态转移方程:dp[i][j]的状态从dp[i-1][j]和dp[i][j-1]的状态得到,即上面放i个数,下面放j个数的状态从上面放i-1个数,下面放j个数的状态 和 上面放i个数,下面放j - 1个数的状态得到。
根据上面所说:
第一行的数字是无条件放置的,我们直接可以将dp[i-1][j]的状态转移到dp[i][j]上去,将第i个数放在第一行,即dp[i][j] += dp[i - 1][j]。
只有当j - 1 < i时,即上一个状态上第一行放的个数大于第二行放的个数,我们才可以进行第二行的放置,将第j个数放在第二行,即dp[i][j] += dp[i][j - 1]。
初始化部分:
根据第一行无条件放置的特性,我们可以进行相应的操作,将dp[i][0] = 1;代表第一行放置i个数,第二行放置0个数的方案数为1,因为第二行没有数字,所以第一行只能顺序走下去嘛。
在循环内部记得模2020哟。
所以我们最后输出的就是dp[1010][1010];
答案就是:1340
代码部分:
#include <bits/stdc++.h>
using namespace std;
const int N = 2025;
int dp[N][N];
int main()
{
int n = 2020;
for (int i = 1; i < 1011; i++)
{
dp[i][0] = 1;
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
dp[i][j] += dp[i][j - 1];
if (i - 1 >= j)
{
dp[i][j] += dp[i - 1][j];
}
dp[i][j] %= 2020;
}
}
cout << dp[1010][1010] << endl;
return 0;
}