题解:CF997 C.Sky Full of Stars

Translation

有一个 \(n\times n \ (1 \leq n \leq 10^6)\) 的正方形网格,用红色,绿色,蓝色三种颜色染色,求有多少种染色方案使得至少一行或一列是同一种颜色。结果对 \(998244353\) 取模。(翻译来自洛谷)

Solution

发现直接求很困难,考虑用容斥简化问题。

发现约束条件「至少一行或一列是同一种颜色」是条件「对于任意 \(i,j\ (i+j \geq 1)\) ,恰好 \(i\)\(j\) 列是同一颜色」的并集。

\(F(i,j)\) 为满足条件「至少有 \(i\)\(j\) 列是同一颜色」的答案,不难发现,该条件是上句话后者的一个交集。

根据容斥原理,答案能表示为:

\[\sum_{i=0}^n\sum_{j=0}^n [i+j\geq 1] \times (-1)^{i+j+1} {n\choose i} {n\choose j} F(i,j) \]

根据基础组合数学知识 \(F(i,j)\) 的值为:

\[F(i,j)=\left\{ \begin{aligned} & 3^i \times 3^{n(n-i)} & & j=0 \\ & 3^j \times 3^{n(n-j)} & & i=0 \\ & 3 \times 3^{(n-i)(n-j)} & & \text{otherwise} \end{aligned} \right. \]

先考虑 \(i = 0\)\(j = 0\) 的情况,直接套即可,答案为:

\[2\cdot\sum_{i=1}^n (-1)^{i+1} {n\choose i} 3^i \cdot 3^{n(n-i)} \]

复杂度 \(\mathcal{O}(n)\)

然后是其他情况,暴力推式子:

\[\begin{aligned} & \sum_{i=1}^n\sum_{j=1}^n (-1)^{i+j+1} {n\choose i} {n\choose j} 3\cdot 3^{(n-i)(n-j)} \\ =\ & 3 \cdot \sum_{i=1}^n (-1)^{i+1} {n\choose i} \sum_{j=1}^n {n\choose j} (-1)^j (3^{n-i})^{n-j} \\ =\ & 3 \cdot \sum_{i=1}^n (-1)^{i+1} {n\choose i} [(3^{n-i}-1)^n - 3^{n(n-i)}] \end{aligned}\]

(前置知识:二项式定理,求和顺序变换)

这样这一块是 \(\mathcal{O}(n\log_2 n)\) 的。

Code(C++):

#include<bits/stdc++.h>
#define forn(i,s,t) for(register int i=(s);i<=(t);++i)
#define form(i,s,t) for(register int i=(s);i>=(t);--i)
using namespace std;
typedef long long LL;
const int N = 1e6+3, Mod = 998244353;
inline LL q_pow(LL p, LL k) {
	LL Ans = 1;
	while(k) {
		(k & 1) && (Ans = Ans * p %Mod);
		p = 1ll * p * p %Mod;
		k >>= 1;
	}
	return Ans;
}
LL fac[N], inv[N];
inline LL C(int n, int k) {
	return 1ll * fac[n] * inv[k] %Mod * inv[n - k] %Mod;
}
int n; LL Ans, res, Pow3[N], Pown[N];
int main() {
	cin >> n;
	fac[0] = 1;
	forn(i,1,n) fac[i] = 1ll * i * fac[i-1] %Mod;
	inv[n] = q_pow(fac[n], Mod - 2);
	form(i,n,1) inv[i-1] = 1ll * i * inv[i] %Mod;
	Pow3[0] = 1;
	forn(i,1,n) Pow3[i] = Pow3[i-1] * 3ll %Mod;
	Pown[0] = 1;
	forn(i,1,n) Pown[i] = Pow3[n] * Pown[i-1] %Mod;
	forn(i,1,n) {          // 情况 1
		if(i & 1) Ans += C(n, i) * Pow3[i] %Mod * Pown[n-i] %Mod;
		else Ans += Mod - C(n, i) * Pow3[i] %Mod * Pown[n-i] %Mod;
		Ans %= Mod;
	}
	Ans = 2ll * Ans %Mod;
	forn(i,1,n) {          // 情况 2
		if(i & 1) res += C(n, i) * (q_pow((Pow3[n-i] - 1), n) - Pown[n-i] + Mod) %Mod;
		else res += Mod - C(n, i) * (q_pow((Pow3[n-i] - 1), n) - Pown[n-i] + Mod) %Mod;
		res %= Mod;
	}
	res = 3ll * res %Mod;
	printf("%d\n", (Ans + res) %Mod);
	return 0;
}
posted @ 2021-02-25 13:49  AxDea  阅读(119)  评论(0编辑  收藏  举报