Codeforces 1051D Bicolorings(三维dp)

Bicolorings
You are given a grid, consisting of 22 rows and nn columns. Each cell of this grid should be colored either black or white.

Two cells are considered neighbours if they have a common border and share the same color. Two cells AA and BB belong to the same component if they are neighbours, or if there is a neighbour of AA that belongs to the same component with BB.

Let’s call some bicoloring beautiful if it has exactly kk components.

Count the number of beautiful bicolorings. The number can be big enough, so print the answer modulo 998244353998244353.

Input

The only line contains two integers n and k(1≤n≤10001≤n≤1000, 1≤k≤2n1≤k≤2n) — the number of columns in a grid and the number of components required.

Output

Print a single integer — the number of beautiful bicolorings modulo 998244353998244353.

Examples

Input

3 4
Output

12
Input

4 1
Output

2
Input

1 2
Output

2
题意:给你一个2 * n的矩阵(算是方格吧)然后你需要去用黑白两种颜色去涂这些1 * 1的方格,其中问如果要分成k块区域的话有多少种方案(只有相邻才算一种情况)
举个栗子:
下面这个是两块区域的
在这里插入图片描述在这里插入图片描述
下面这个是四块区域的
在这里插入图片描述
明白了题意之后就需要去分析了;
先附上两位大佬的参考:
https://www.cnblogs.com/tobyw/p/9685639.html
https://blog.csdn.net/bao___zi/article/details/82800091
在这里我建议大家画一下图,将1 * 2和2 * 2的画出来,在画的过程中你会发现,每增加一列的时候就会用到前一列的情况,那么熟悉dp的小伙伴就会想到去找状态转移方程了(其实也算是递推关系式吧),因为有这样一种情况:
当放置到底i列的时候可能的情况会有许多种,也就是说会有分成多组区域,那么就可以定义如下的dp数组了:
定义dp[i][j]代表前i列分成j组区域的方案数;
但是只这样去定义还是不太合适的,因为你有两种方式去放置(其实本质上是4种,但是这不影响,如果想定义成4组的话可以去看我参考的第一位大佬的解析),一种是全涂一种颜色,另外一种方式是涂成两种颜色,那么最后需要去定义成:
dp[i][j][0]代表前i列分成j组区域并且第i列全涂一种颜色的方案数;
dp[i][j][1]代表前i列分成j组区域并且第i列涂两种颜色的方案数;
首先你会得到:dp[1][1][0]=dp[1][2][1]=2;
那么我先放上两个递推关系式:
dp[i][j][0]=(dp[i-1][j][1]*2)%MOD+dp[i-1][j-1][0]+dp[i-1][j][0];
当涂第j列全为1一种颜色的时候,那么它就与前一种状态,即前i-1列为j组区域切最后一列是两种颜色有关,你会发现,当最后一列是一种颜色的时候,是不会影响答案的,什么意思呢:
在这里插入图片描述
就想是这个图片当前的状态是dp[2][2][1],那么dp[3][2][0]是不是再加一列同样颜色的不影响区域的划分呢,也就是不会增减区域的,因为是有全黑和全白两种方案,所以就需要乘以2,剩下的也是同样的方式去理解了
dp[i][j][1]=(dp[i-1][j-1][0]*2)%MOD+dp[i-1][j-2][1]+dp[i-1][j][1];
这个等式我说一下为什么是要加dp[i-1][j-2][1]:
在这里插入图片描述
如果当前dp[i-1][j][1]的其中一种涂色方案是这样的,那么你在加一列上黑下白的不就是多了两块区域吗,所以你需要的是少两块区域的状态,也就是dp[i-1][j-2][1]了

#include <iostream>
#include <algorithm>
#include <string>
#include<cstring>
#include<cmath>
#include<queue>
#include <cstdio>
#include <vector>
#include<set>
using namespace std;
typedef long long ll;
const int N= 1e6+10;
const int INF=0x3f3f3f3f;
const int MOD=998244353;
#define rep(i,a,b) for(int i=a;i<=b;i++)
ll dp[1010][2020][2];
int main()
{
//	ios::sync_with_stdio(0);
//	cin.tie(0);cout.tie(0);
	#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
	#endif
	int n,k;
	scanf("%d%d",&n,&k);
	dp[1][1][0]=dp[1][2][1]=2;
	for(int i=2;i<=n;i++){
		for(int j=1;j<=i*2;j++){
			dp[i][j][0]=(dp[i-1][j][1]*2)%MOD+dp[i-1][j-1][0]+dp[i-1][j][0];
			dp[i][j][0]%=MOD;
			dp[i][j][1]=(dp[i-1][j-1][0]*2)%MOD+dp[i-1][j-2][1]+dp[i-1][j][1];
			dp[i][j][1]%=MOD;
		}
	}
	printf("%lld\n",(dp[n][k][0]+dp[n][k][1])%MOD);
	return 0;
}


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用\[1\]中提到了一种树形动态规划的方法来解决CodeForces - 982C问题。在这个问题中,subtree指的是子连通块,而不是子树。为了使cnt_white - cnt_black尽可能大,可以使用两次树形动态规划来求解。第一次是自底向上的过程,维护一个dp数组,表示以每个节点为根的子树中的最大连通块。第二次是自顶向下的过程,处理自底向上过程中无法包含的树链所代表的子树。在第二次遍历中,需要维护一个sum变量,用于存储树链所代表的子树的贡献。根据ans\[u\]的正负,决定是否能对相邻的子节点做出贡献。如果ans\[u\]为正,则减去dp\[v\]就是树链所代表的子树的权值。最终,ans\[u\]代表包含节点u在内的子连通块的最大权值。\[1\] 问题: CodeForces - 982C 树形DP是什么问题?如何解决? 回答: CodeForces - 982C是一个树形动态规划问题。在这个问题中,需要求解子连通块的最大权值和,使得cnt_white - cnt_black尽可能大。解决这个问题的方法是使用两次树形动态规划。第一次是自底向上的过程,维护一个dp数组,表示以每个节点为根的子树中的最大连通块。第二次是自顶向下的过程,处理自底向上过程中无法包含的树链所代表的子树。在第二次遍历中,需要维护一个sum变量,用于存储树链所代表的子树的贡献。根据ans\[u\]的正负,决定是否能对相邻的子节点做出贡献。最终,ans\[u\]代表包含节点u在内的子连通块的最大权值。\[1\] #### 引用[.reference_title] - *1* *2* [CodeForces - 1324F Maximum White Subtree(树形dp)](https://blog.csdn.net/qq_45458915/article/details/104831678)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值