Loading

CF869C The Intriguing Obsession(排列组合)

链接:https://ac.nowcoder.com/acm/contest/21791/E
来源:牛客网

题目描述
岛上有三种颜色的岛屿,分别是红色、蓝色和紫色。岛群分别由

a
,
b
a,b和

c
c个不同的岛组成。

在一些(可能全部或没有)岛屿之间建立了桥梁。一座桥双向连接两个不同的岛,长度为

1
1。对于任意两个相同颜色的岛,要么不能通过桥相互到达,要么它们之间的最短距离至少为

3
3。

Fire Sisters 已准备好迎接未知,但他们也想测试您的勇气。你来这里是为了找出在约束条件下建造所有桥梁的不同方法的数量,并给出模

998244353
998244353 的答案。如果存在一对岛,它们之间有一座桥,但另一种没有桥,则两种方法被认为是不同的。
输入描述:
输入包含三个空格分隔的整数

a
,
b
,
c

1

a
,
b
,
c

5000

a,b,c(1≤a,b,c≤5000),分别表示岛群中红色、蓝色和紫色的岛数。
输出描述:
输出一行包含一个整数,表示构建桥梁的不同方法的数量,模

998244353
998244353。
示例1
输入

复制
1 1 1
输出

复制
8
说明

在这个例子中,有 3 座可能建造的桥,并且没有任何桥的设置违反限制。因此答案是

2
3

8
2
3
=8。
示例2
输入

复制
1 2 2
输出

复制
63
说明

下图中,上方两个是有效结构,而下方两个是无效的。

示例3
输入

复制
1 3 5
输出

复制
3264
示例4
输入

复制
6 2 9
输出

复制
813023575

根据题意,两个同色的岛之间的最短距离为3等价于两个同色的岛屿之间不能有边相连,同时两个同色的岛屿也不能同时连接到同一个岛。这样就好办了,对于每两种颜色可以计算这两种颜色的岛之间的连边的方案数,然后由乘法原理把这三种方案数乘起来即可。对于A和B这两种颜色,如果他们之间的岛屿连边一定是一个类似二分图的形式,只需要枚举连的边的数量然后用组合数计算方案即可。形式化地来说,对于输入的a和b,若这两种颜色的岛屿的连边数为i,那么方案数就是\(C_{a}^{i}\times C_{b}^{i}\times i!\),阶乘的话也很好理解。


// Created on 解志国的iPad.

#include <iostream>
#define ll long long
#define LL long long
#define mod 998244353
#define p 998244353
using namespace std;
ll a, b, c, ans = 1;
ll F(ll x) {
    ll ans = 1;
    for(int i = 1; i <= x; i++) {
        ans = ans * i % mod;
    }
    return ans;
}
const int maxn=1000005;
void extend_gcd(LL a,LL b,LL &x,LL &y){
    if(b==0){
        x=1,y=0;
        return;
    }
    extend_gcd(b,a%b,y,x);
    y-=a/b*x;
}

LL inv[maxn+10];
LL f[maxn+10];
void init(){//阶乘及其逆元打表
    f[0]=1;
    for(int i=1;i<=maxn;i++){
        f[i]=f[i-1]*i%p;
    }

    LL x,y;
    extend_gcd(f[maxn],p,x,y);//先求出f[N]的逆元,再循环求出f[1~N-1]的逆元
    inv[maxn]=(x%p+p)%p;
    for(int i=maxn-1;i>=1;i--){
        inv[i]=inv[i+1]*(i+1)%p;
    }
}

LL C(LL n,LL m){
    if(n==m||m==0)return 1;
    return (f[n]*inv[m]%p*inv[n-m]%p)%p;
}
int main() {
    init();
    cin >> a >> b >> c;
    ll ta = 0, tb = 0, tc = 0;
    for(ll i = 0; i <= min(a, b); i++) {
        ta = (ta + (C(a, i) * C(b, i) % mod * F(i) % mod) % mod) % mod;
    }
    for(ll i = 0; i <= min(b, c); i++) {
        tb = (tb + (C(b, i) * C(c, i) % mod * F(i) % mod) % mod) % mod;
    }
    for(ll i = 0; i <= min(a, c); i++) {
        tc = (tc + (C(a, i) * C(c, i) % mod * F(i) % mod) % mod) % mod;
    }
    cout << ta * tb % mod * tc % mod;
    return 0;
}

posted @ 2021-10-22 16:53  脂环  阅读(54)  评论(0编辑  收藏  举报