Mio visits ACGN Exhibition

本文介绍了一道编程竞赛题目,涉及到二维动态规划的应用。题目要求在限制路径的ACGN展览中,计算从起点到终点满足特定0和1数量的路径总数。通过分析,可以构建三维动态规划状态并进行转移,最后处理边界条件,得出答案。该问题的难点在于状态转移方程的建立和遍历顺序的设计。
摘要由CSDN通过智能技术生成

A. Mio visits ACGN Exhibition

time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

One day, Mio visits an Animation Comic Game Novel (ACGN) Exhibition, and she would like to buy some presents for Ritsu.

We assure that the space of the exhibition is a n×mn×m grid, called the grid AA, and each cell in the grid represents a stall, only selling present 00 or 11. In other words, every cell of the n×mn×m grid AA is filled with 00 or 11.

Under the control policy for containing COVID-19, there are some restrictions on visiting route.

We define a SAFE PATH as a path from the top left cell (1,1)(1,1), to the bottom right cell (n,m)(n,m), and if you are in the cell (x,y)(x,y), then you can only travel to the cells (x+1,y)(x+1,y) or (x,y+1)(x,y+1). Every visitor has to visit the exhibition through SAFE PATH, so does Mio.

The two paths are considered to be different if and only if at least one cell passed differs.

Mio wonders how many different SAFE PATHs, which have some 00s and 11s, and the number of 00 is at least pp, the number of 11 is at least qq.

Since the answer may be too large, you only need to output the result modulo 998244353998244353.

Input

The first line contains four integers, nn, mm, pp, qq (1≤n,m≤500,0≤p,q≤100001≤n,m≤500,0≤p,q≤10000).

Each of the next nn lines contains mm space separated integers Ai,jAi,j (0≤Ai,j≤1)(0≤Ai,j≤1), denoting the number in the cell (i,j)(i,j) of the grid AA.

Output

Print a single integer, denoting the answer to the question, modulo 998244353998244353.

Examples

input

Copy

2 2 1 1
0 0
1 1

output

Copy

2

input

Copy

3 3 2 0
0 0 1
0 0 1
1 0 0

output

Copy

6

题意:一个n * m 的矩阵,矩阵由0和1构成,p,q分别代表从(1,1)这一点到(n,m)这一点,需要经过的至少0,1个数,问这样的路径有几条,

用dfs对于本题来说是2的n次方,绝对超时,这时就要想和dfs捆绑的动态规划,动态规划可以将时间压缩很多,可以写三维的动态规划方程,dp[i][j][k], i代表的是从哪一行转移,j代表的是从哪一列转移,k代表的是到dp[i][j]走过的0的个数,dp[i][j][k]的值代表的是走过k个0的路径总数。

搞清楚各个下标的含义,构造dp就看需要什么,就构造几维。

注意到,其实转移只可能是从当前点所在行的上一行,和当前行两行转移,那么可以把i改成2,就两种状态,初始状态,当第一个点为1,那么,dp[1][1][0] = 1, 第一个1也可以是0,随便假设,第二个就是列数,第三个就是走过0个0,反之dp[1][1][1] = 0;

最后就是遍历从k = p; n +m - 1 - k >= q; ++k

状态转移 当当前点是0时 dp[i][j][k] = dp[i][j - 1][k - 1] + dp[i ^ 1][j][k - 1]等于可以走到他的两个路径总数相加,当当前点是1时dp[i][j][k] = dp[i][j - 1][k] + dp[i ^ 1][j][k]等于简单的相加。

其实想到以上看着简单,但其实还是有难度的,首先是三维,还有就是最后一维是记录走过了几个0,最后一步这个遍历想到最后来处理,也是很难想到的,但其实是一环扣一环,还是按照题目意思来,他要求几个,那我就要记录下来,然后遍历。

最后就是用long long 会超时,以后能不用long long 就别用

#include <bits/stdc++.h>
//#define int long long
#define ISO ios::sync_with_stdio(false)
using namespace std;
const int N = 5e2 + 10;
const int mod = 998244353;
int n, m, p0, q1;
int a[N][N];
int dp[2][N][2 * N + 10];// 值为路径数 

signed main()
{
	ISO; cin.tie(0), cout.tie(0);
	cin >> n >> m >> p0 >> q1;
	for (int i = 1; i <= n; ++i)
	{
		for (int j = 1; j <= m; ++j)
			cin >> a[i][j];
	}
	int s = 1;
	if (a[1][1] == 1)
		dp[1][1][0] = 1;
	else
		dp[1][1][1] = 1;
	for (int i = 1; i <= n; ++i)
	{
		for (int j = 1; j <= m; ++j)
		{
			if (i == 1 && j == 1)
					continue;
			for (int k = 0; k <= n + m - 1; ++k)
			{
				if (a[i][j] == 1)
				{
					dp[s][j][k] = dp[s ^ 1][j][k] + dp[s][j - 1][k];
				}
				else if (a[i][j] == 0)
				{
					dp[s][j][k] = dp[s ^ 1][j][k - 1] + dp[s][j - 1][k - 1];
				}
				dp[s][j][k] = dp[s][j][k] % mod;
			}
			
		}
		s = s ^ 1;
	}		
	s = s ^ 1;
	int ans = 0;
	for (int k = p0; n + m - k - 1 >= q1; ++k)
	{
		ans = ans + dp[s][m][k];
		ans = ans % mod;
	}
	cout << ans << endl;
	return 0;
} 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值