题解 CF1503E 2-Coloring [*easy]

感觉这题是一道细节比较多但是不难的题,配不上这个 *3100 的标签,连萌新都能独立做出来......

题面

给定一个 (n imes m) 的矩阵,要你把矩阵的每一个格子染成蓝的或黄的,要求每一行的蓝色格子段数(连通块数)恰好有一个,每一列的黄格子段数恰好有一个。求染色方案数,答案对 (998244353) 取模。

数据范围:(1 le n, m le 2000)

题解

这里的 (n, m) 可能是反的,但是不影响答案(

观察蓝色的线段。

经过手膜大致可以发现可以分成两类情况讨论

第一类

蓝色的分成两个部分,上面一个下面一个。

这两个部分都是 "单峰" 的。

要求两个部分的 "高度" 之和恰好为 (m)

考虑美剧第一个的高度和两个峰值的位置(枚举最左边的或最右边的即可)

[2 sumlimits_{z = 1}^{m - 1} sumlimits_{i = 1}^{n - 1} sumlimits_{j = i + 1}^{n} inom{i + z - 1}{z} inom{n - i + z - 1}{z - 1} inom{j + m - z - 2}{m - z - 1} inom{n - j + m - z}{m - z} ]

第二类

蓝色的分成两个部分,上面一个下面一个。

要求两个部分的 "高度" 之和 (> m)

枚举高度,然后枚举这个交的部分(黑线)的 (x) 坐标即可。

[2 sumlimits_{p = 1}^{n} sumlimits_{i = 1}^{m - 1} sumlimits_{j = m - i + 1}^{m - 1} inom{p + i - 1}{i} inom{n - p + m - j - 1}{m - j - 1} inom{p + m - i - 1}{m - i - 1} inom{n - p + j - 1}{j} ]

现在的复杂度是 (Theta(n^3)) 的((n, m) 同阶)

但是这两个柿子是可以前缀和优化的,做到 (Theta(n^2))


上面这些柿子是哪里来的?

考虑一个长为 (x) 的不严格单调下降序列,要求第一个值 (le y)

这个是经典的插板法,先化成严格的,然后再插板,一个板代表这个序列的一个元素。那么答案就是 (inom{x+y}{x})

那里要乘以 (2) 是因为我们钦定了上面和下面的左右关系。

你有没有感觉这两个柿子是一模一样的?

嗯是的,其实这两种情况只是 (n. m) 交换了一下,本质是差不多的(

代码

#include<bits/stdc++.h>
#define L(i, j, k) for(int i = j, i##E = k; i <= i##E; i++)
#define R(i, j, k) for(int i = j, i##E = k; i >= i##E; i--)
#define ll long long
#define pii pair<int, int>
#define db double
#define x first
#define y second
#define ull unsigned long long
#define sz(a) ((int) (a).size())
#define vi vector<int>
using namespace std;
const int N = 4e5 + 7, mod = 998244353;
int ns, n, m;
int fac[N], inv[N], ifac[N];
void init(int x) {
	fac[0] = ifac[0] = inv[1] = 1;
	L(i, 2, x) inv[i] = (ll) inv[mod % i] * (mod - mod / i) % mod;
	L(i, 1, x) fac[i] = (ll) fac[i - 1] * i % mod, ifac[i] = (ll) ifac[i - 1] * inv[i] % mod;
}
int C(int x, int y) {
	return x < y || y < 0 ? 0 : (ll) fac[x] * ifac[y] % mod * ifac[x - y] % mod;
}
int main() {
	cin >> n >> m, init(max(n, m) * 4);
	L(z, 1, m - 1) {
		int now = 0;
		R(r1, n - 1, 1) {
			(now += (ll) C(r1 + m - z - 1, m - z - 1) * C(n - r1 + m - z - 1, m - z) % mod) %= mod;
			(ns += (ll) C(r1 + z - 1, z) * C(n - r1 + z - 1, z - 1) % mod * now % mod) %= mod;
		}
	}
	L(p, 1, n) {
		int now = 0;
		L(z1, 1, m - 1) {
			(now += (ll) C(n - p + z1 - 2, z1 - 2) * C(n - p + m - z1, m - z1 + 1) % mod) %= mod; 
			(ns += (ll) C(p + z1 - 1, z1) * C(p + m - z1 - 1, m - z1 - 1) % mod * now % mod) %= mod;	
		}
	}
	ns = (ll) ns * 2 % mod;
	cout << ns << "
";
	return 0;
} 

祝大家学习愉快!

原文地址:https://www.cnblogs.com/zkyJuruo/p/14616877.html