AcWing 十一届蓝桥杯-结果填空. 矩阵
原题链接
简单
作者:
以凝
,
2021-04-15 17:37:13
,
所有人可见
,
阅读 244
题目
把1~2020放在2×1010的矩阵里。
要求同一行中右边的比左边大,同一列中下边的比上边的大。一共有多少种方案?
答案很大,你只需要给出方案数除y以2020的余数即可。
答案提交
这是一道结果填空题, 你只需要算出结果后提交即可。
本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
答案
1340
建议先学习杨老师的照相排列
,然后这道题目就是降维打击了。本题接连接就是杨老师的照相排列
。
点评 : 这是一类线性dp ,在每一维度上进行dp
本题题目说,要满足 “下面的数字和右边的数字大于本数字” ,
让人不自觉地想起深搜解决。但其实动动笔模拟一下,就会发现,
这样的排列虽然方案数很大,但是排列下来的方式很受限制。
中规中矩来讲,我们只能一个一个数字,从小到大来枚举,从左至右紧凑放置。
于是,一个看似刻意的要求成为了一件很自然的事情(按照上述排放方式
自然得到一个符合要求的矩阵)。接下来,我们需要集中精力思考如何求,通过上述方式
排列求得相应的方案数。
第一维度 : 第一行数字个数
第二维度 : 第二行数字个数
于是状态转移方程基本是:
f[a][b] = f[a-1][b] + f[a][b-1] ;
表示 新状态f[a][b]是
(1)新数字放在第一排
(2)新数字放在第二排
两种情况的方案数求和得来的。
#include<bits/stdc++.h>
using namespace std ;
typedef long long LL ;
const int N = 1100 ;
const int mod = 2020 ;
int n ;
LL f[N][N] ;
int main()
{
f[0][0] = 1 ;
for(int a = 0; a <= 1010 ; a ++)
{
for(int b = 0 ; b <= 1010&& b<=a ; b++)
{
LL &v = f[a][b] ;
if(a) v = (v + f[a-1][b]) % mod ;
if(b) v = (v+f[a][b-1]) % mod ;
}
}
cout << f[1010][1010] % mod ;
return 0 ;
}