[Codeforces 869C]The Intriguing Obsession(组合数学)

Address

http://codeforces.com/problemset/problem/869/C

Meaning

有三种不同类型的小岛,方便地,各自涂上了红,蓝,紫三色。每种颜色的小岛各自有 a b c 个。
这些小岛之间初始时互相分离。可以在小岛之间架桥,两个小岛间最多架一座桥。
但要满足:任意两个不同的颜色相同的小岛的最短距离要大于等于 3 (桥的长度为 1 )。
你需要计算出不同的架桥方案有多少种,如果有两个小岛之间造桥的方案变了,我们就说这两个造桥的方案不同。答案对 998244353 取模。
1 a , b , c 5000

Solution

第一眼发现「最短距离大于等于 3 」不容易做。
可以把它转化为「最短距离不小于等于 2 」。
转化了有什么用呢?可以将条件等价化为:
(1)任意两个同色的点之间没有边。
(2)任意一个点 u 发出的任意两条边 ( u , v ) ( u , w ) 的另一端 v , w 异色。
于是我们先在红色和蓝色的点之间连边,然后在红色和紫色的点之间连边,最后在蓝色和紫色的点之间连边。
假设在红色的点中选出了指定的 i 个点,将这 i 个红色点分别与 i 个蓝色点连边,这样的方案数显然为 A b i
所以,在红色和蓝色点之间连边的方案数为:

i = 0 min ( a , b ) C a i A b i

到这里,最终答案也得出了:
( i = 0 min ( a , b ) C a i A b i ) ( i = 0 min ( a , c ) C a i A c i ) ( i = 0 min ( b , c ) C b i A c i )

Code

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
using namespace std;
const int N = 5005, PYZ = 998244353;
int a, b, c, fac[N], inv[N], ans1, ans2, ans3;
int A(int n, int m) {
    return 1ll * fac[n] * inv[n - m] % PYZ;
}
int C(int n, int m) {
    return 1ll * fac[n] * inv[m] % PYZ * inv[n - m] % PYZ;
}
int main() {
    int i; cin >> a >> b >> c; fac[0] = 1;
    For (i, 1, 5000) fac[i] = 1ll * fac[i - 1] * i % PYZ;
    inv[0] = inv[1] = 1;
    For (i, 2, 5000)
        inv[i] = 1ll * (PYZ - PYZ / i) * inv[PYZ % i] % PYZ;
    For (i, 2, 5000) inv[i] = 1ll * inv[i] * inv[i - 1] % PYZ;
    For (i, 0, min(a, b))
        ans1 = (ans1 + 1ll * C(a, i) * A(b, i) % PYZ) % PYZ;
    For (i, 0, min(a, c))
        ans2 = (ans2 + 1ll * C(a, i) * A(c, i) % PYZ) % PYZ;
    For (i, 0, min(b, c))
        ans3 = (ans3 + 1ll * C(b, i) * A(c, i) % PYZ) % PYZ;
    cout << 1ll * ans1 * ans2 % PYZ * ans3 % PYZ << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xyz32768/article/details/81086282