Address
http://codeforces.com/problemset/problem/869/C
Meaning
有三种不同类型的小岛,方便地,各自涂上了红,蓝,紫三色。每种颜色的小岛各自有
,
,
个。
这些小岛之间初始时互相分离。可以在小岛之间架桥,两个小岛间最多架一座桥。
但要满足:任意两个不同的颜色相同的小岛的最短距离要大于等于
(桥的长度为
)。
你需要计算出不同的架桥方案有多少种,如果有两个小岛之间造桥的方案变了,我们就说这两个造桥的方案不同。答案对
取模。
。
Solution
第一眼发现「最短距离大于等于
」不容易做。
可以把它转化为「最短距离不小于等于
」。
转化了有什么用呢?可以将条件等价化为:
(1)任意两个同色的点之间没有边。
(2)任意一个点
发出的任意两条边
的另一端
异色。
于是我们先在红色和蓝色的点之间连边,然后在红色和紫色的点之间连边,最后在蓝色和紫色的点之间连边。
假设在红色的点中选出了指定的
个点,将这
个红色点分别与
个蓝色点连边,这样的方案数显然为
。
所以,在红色和蓝色点之间连边的方案数为:
到这里,最终答案也得出了:
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;
}