CodeForces 1931G One-Dimensional Puzzle

洛谷传送门

CF 传送门

什么 [ABC336G] 16 Integers 究极弱化版。

把元素 \(1\) 看成 \(01\),元素 \(2\) 看成 \(10\),元素 \(3\) 看成 \(11\),元素 \(4\) 看成 \(00\)。则转化为统计长度为 \(2\) 的子串 \(xy\) 出现次数为 \(c_{xy}\)\(01\) 串个数。

把子串 \(xy\) 看成 \(x \to y\) 的一条有向边,那么这是一个点数为 \(2\)欧拉路径计数问题,可以 BEST 定理解决,但是不需要。

有解的必要条件是 \(|c_{01} - c_{10}| \le 1\)。若 \(c_{01} = c_{10}\) 那么 \(01\) 串开头和结尾的字符相同。若以 \(0\) 开头和结尾,相当于把 \(c_{00} + c_{01} + 1\)\(0\) 分成 \(c_{01} + 1\) 份,\(c_{10} + c_{11}\)\(1\) 分成 \(c_{10}\) 份,每份非空,根据插板法可得方案数为 \(\binom{c_{00} + c_{01}}{c_{01}} \binom{c_{10} + c_{11} - 1}{c_{10} - 1}\)。以 \(1\) 开头和结尾类似。

\(c_{01} = c_{10} + 1\),那么以 \(0\) 开头,以 \(1\) 结尾。相当于把 \(c_{00} + c_{01}\)\(0\) 分成 \(c_{01}\) 份,\(c_{11} + c_{01}\)\(1\) 分成 \(c_{01}\) 份,方案数为 \(\binom{c_{00} + c_{01} - 1}{c_{01} - 1} \binom{c_{11} + c_{01} - 1}{c_{01} - 1}\)

\(c_{10} = c_{01} + 1\) 的情况是类似的。注意特判 \(c_{10} = c_{01} = 0\),这种情况只能是全 \(0\) 或全 \(1\),所以 \(c_{00}\)\(c_{11}\) 不能都非 \(0\)

时间复杂度 \(O(T + \sum c_i)\)

code
// Problem: G. One-Dimensional Puzzle
// Contest: Codeforces - Codeforces Round 925 (Div. 3)
// URL: https://codeforces.com/contest/1931/problem/G
// Memory Limit: 256 MB
// Time Limit: 4000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int N = 4000000;
const ll mod = 998244353;

inline ll qpow(ll b, ll p) {
	ll res = 1;
	while (p) {
		if (p & 1) {
			res = res * b % mod;
		}
		b = b * b % mod;
		p >>= 1;
	}
	return res;
}

int c00, c01, c10, c11;
ll fac[N + 5], ifac[N + 5];

inline void init() {
	fac[0] = 1;
	for (int i = 1; i <= N; ++i) {
		fac[i] = fac[i - 1] * i % mod;
	}
	ifac[N] = qpow(fac[N], mod - 2);
	for (int i = N - 1; ~i; --i) {
		ifac[i] = ifac[i + 1] * (i + 1) % mod;
	}
}

inline ll C(ll n, ll m) {
	if (n < m || n < 0 || m < 0) {
		return 1;
	} else {
		return fac[n] * ifac[m] % mod * ifac[n - m] % mod;
	}
}

void solve() {
	scanf("%d%d%d%d", &c01, &c10, &c11, &c00);
	if (abs(c01 - c10) >= 2) {
		puts("0");
		return;
	}
	if (c01 == 0 && c10 == 0) {
		puts(((c00 ? 1 : 0) + (c11 ? 1 : 0)) == 2 ? "0" : "1");
		return;
	}
	if (c01 == c10) {
		printf("%lld\n", (C(c11 + c10 - 1, c10 - 1) * C(c01 + c00, c01) + C(c11 + c10, c10) * C(c01 + c00 - 1, c01 - 1)) % mod);
	} else if (c01 == c10 + 1) {
		printf("%lld\n", C(c11 + c01 - 1, c01 - 1) * C(c01 + c00 - 1, c01 - 1) % mod);
	} else {
		printf("%lld\n", C(c11 + c10 - 1, c10 - 1) * C(c10 + c00 - 1, c10 - 1) % mod);
	}
}

int main() {
	init();
	int T = 1;
	scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

posted @ 2024-02-14 10:46  zltzlt  阅读(67)  评论(0编辑  收藏  举报