cf869 C. The Intriguing Obsession(排列组合)

https://codeforces.com/contest/869/problem/C

题意:

有三种颜色的岛屿,数量分别为 \(A,B,C\)

在一些(可能全部或没有)岛屿之间建立了桥梁。一座桥双向连接两个不同的岛。对于任意两个相同颜色的岛甲和乙,要么甲不能到达乙,要么甲要经过至少3座桥才能到达乙

岛两两不同,问造桥方案总数。答案对998244353取模

思路:

两种不合法的造桥方式:\(a_i-a_j\)\(a_i-b_k-a_j\) ,其中 \(a_i\)\(a_j\) 为两个同色岛,\(b_k\) 不同色

\(A\)\(B\) 之间造桥不会影响在 \(B\)\(C\) 之间造桥,也不会影响在 \(A\)\(C\) 之间造桥

\(A\)\(B\) 之间造桥的方案数为 \(f1=\Sigma_{k=0}^{min(A,B)} k!C_A^k C_B^k\) ,总方案数量为 \(f1*f2*f3\)

\(A,B,C\le 5000\) ,可以预处理阶乘,快速幂求逆元。也可以杨辉三角预处理组合数

#include <bits/stdc++.h>
using namespace std;

const signed N = 5000;
const int p = 998244353;

int ksm(int a, int b)
{
    a %= p;
    int res = 1;
    while(b)
    {
        if(b & 1) res = 1ll*res * a % p;
        a = 1ll*a * a % p;
        b >>= 1;
    }
    return res;
}
int jie[N+10];
void init()
{
    jie[0] = 1;
    for(int i = 1; i <= N; i++) jie[i]=1ll*i*jie[i-1]%p;
}
int inv(int x)
{
    return ksm(x,p-2);
}
int C(int n, int m)
{
    return 1ll*jie[n]*inv(1ll*jie[m]*jie[n-m]%p)%p;
}
int solve(int x, int y)
{
    int ret = 0;
    for(int i = 0; i <= min(x,y); i++)
        ret=(ret+1ll*C(x,i)%p*C(y,i)%p*jie[i]%p)%p;
    return ret;
}
signed main()
{
    init();
    int a, b, c; cin >> a >> b >> c;
    cout << 1ll*solve(a,b)*solve(b,c)%p*solve(a,c)%p;

    return 0;
}

附上一个杨辉三角预处理组合数的做法

int C[N+10][N+10];
void initC()
{
    for(int i = 1; i <= N; i++) C[i][0] = C[i][i] = 1;
    for(int i = 1; i <= N; i++)
        for(int j = 1; j < i; j++)
            C[i][j] = (C[i-1][j-1]+C[i-1][j])%p;
}
int solve(int x, int y)
{
    int ret = 0;
    for(int i = 0; i <= min(x,y); i++)
        ret=(ret+1ll*C[x][i]*C[y][i]%p*jie[i]%p)%p;
    return ret;
}
posted @ 2021-10-23 12:24  Bellala  阅读(96)  评论(0)    收藏  举报