【CodeForces 997C】Sky Full of Stars(组合计数)

本文提供了一道名为SkyFullofStars的编程题解,该题要求计算特定条件下n×n网格的染色方案数量。文章详细介绍了如何通过数学推导简化原始问题,并给出了一种在大数据范围内也能高效求解的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:【CodeForces 997C】Sky Full of Stars

官方题解:Codeforces Round #493 — Editorial

题目大意:有一个 n×n n × n 的网格和三种颜色,问有多少种染色方案,使得至少一行或者一列颜色一样。 n106 n ≤ 10 6

如果 n3000 n ≤ 3000 ,那么直接暴力容斥即可。
算式: answer=i=0...n,j=0...n,i+j>0CinCjn(1)i+j+13(ni)(nj)+1 a n s w e r = ∑ i = 0... n , j = 0... n , i + j > 0 C n i C n j ( − 1 ) i + j + 1 3 ( n − i ) ( n − j ) + 1

但是因为 n n 的数据范围较大,我们考虑将式子变形。
考虑将i=0 or j=0的情况拎出来算,时间复杂度 O(nlogn) O ( n log ⁡ n )
余下的式子: answer=ni=1nj=1CinCjn(1)i+j+13(ni)(nj)+1 a n s w e r = ∑ i = 1 n ∑ j = 1 n C n i C n j ( − 1 ) i + j + 1 3 ( n − i ) ( n − j ) + 1
换元后得到: answer=3n1i=0n1j=0CinCjn(1)i+j+13ij a n s w e r = 3 ∑ i = 0 n − 1 ∑ j = 0 n − 1 C n i C n j ( − 1 ) i + j + 1 3 i j
整理后得到: answer=3n1i=0Cin(1)i+1n1j=0Cjn(3i)j a n s w e r = 3 ∑ i = 0 n − 1 C n i ( − 1 ) i + 1 ∑ j = 0 n − 1 C n j ( − 3 i ) j

(a+b)n=ni=0Cinaibni ( a + b ) n = ∑ i = 0 n C n i a i b n − i ,得到
answer=3n1i=0Cin(1)i+1[(1+(3i))n(3i)n] a n s w e r = 3 ∑ i = 0 n − 1 C n i ( − 1 ) i + 1 [ ( 1 + ( − 3 i ) ) n − ( − 3 i ) n ]

这个式子有 n n 项,计算的复杂度为O(nlogn)

#include <cstdio>
const int maxn = 1000005;
const int mod = 998244353;
int res, ans, n;
int fac[maxn], inv[maxn];
void update(int &x, int y) {
    x += y;
    if (x < 0) {
        x += mod;
    }
    if (x >= mod) {
        x -= mod;
    }
}
int mpow(int x, int y) {
    update(x, 0);
    int z = 1;
    for (; y; y >>= 1) {
        if (y & 1) {
            z = 1ll * z * x % mod;
        }
        x = 1ll * x * x % mod;
    }
    return z;
}
int calc(int x, int y) {
    return 1ll * fac[x] * inv[y] % mod * inv[x - y] % mod;
}
int main() {
    scanf("%d", &n);
    fac[0] = 1, inv[0] = 1;
    for (int i = 1; i <= n; i++) {
        fac[i] = 1ll * fac[i - 1] * i % mod;
        inv[i] = mpow(fac[i], mod - 2);
    }
    for (int i = 1; i <= n; i++) {
        int a = 1ll * calc(n, i) * mpow(-1, i + 1) % mod;
        int x = mpow(3, (1ll * n * (n - i) + i) % (mod - 1));
        update(ans, 1ll * a * x % mod);
    }
    ans = 2 * ans % mod;
    for (int i = 0; i < n; i++) {
        int t = mod - mpow(3, i);
        int x = (mpow(t + 1, n) + mod - mpow(t, n)) % mod;
        int a = 1ll * calc(n, i) * mpow(-1, i + 1) % mod;
        update(res, 1ll * a * x % mod);
    }
    res = 3ll * res % mod;
    printf("%d\n", (ans + res) % mod);
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值