前言
这一题我比赛时写挂了,比赛后又改对了……
题意
有一张 n n n 个点, m m m 条边的无向图,其中每一个点都被涂成红或蓝,而且恰好要染红 k k k 个点,使得两端点不同色的边的数目为偶数,输出方案数。
思路
对于条件 2 2 2,我们可以转化一下,现在我们假设红蓝边为 a a a,红红边为 b b b,那么对于我们选择的 k k k 个点,这 k k k 个点的总边数为 a + 2 b a+2b a+2b,所以我们可以发现 a a a 和总边数同奇偶,那么条件二就可以转化为 k k k 个点的总边数为偶数。因为总边数为偶数,那么奇数点为偶数个,所以我们枚举奇数点。
代码实现
#include<bits/stdc++.h>
using namespace std;
#define int long long//注意一定要开long long
const int mod = 998244353;
vector<int> g[200005];
int fact[200005];
int infact[200005];
int ji = 0;
int ou = 0;
int _pow(int a, int b) {//快速幂a^ b下面会用到
int res = 1;
while (b) {
if (b & 1) {
res = res * a % mod;
}
a = a * a % mod;
b >>= 1;
}
return res;
}
void ini() {
fact[0] = 1;
infact[0] = 1;
for (int i = 1; i <= 200000; i++) {
fact[i] = fact[i - 1] * i % mod;
infact[i] = infact[i - 1] * _pow(i, mod - 2) % mod;
}
}
int c(int a, int b) {//组合数C
if (a < b) {
return 0;
}
return fact[a] * infact[b] % mod * infact[a - b] % mod;
}
signed main() {
int n, m, k;
ini();
cin >> n >> m >> k;
for (int i = 1; i <= m; i++) {
int u, v;
cin >> u >> v;
g[u].push_back(v);//建图
g[v].push_back(u);//双向边
}
for (int i = 1; i <= n; i++) {
if (g[i].size() % 2) {
ji++;//
} else {
ou++;//
}
}
int ans = 0;
for (int i = 0; i <= k; i += 2) {
ans += c(ji, i) * c(ou, k - i) % mod;
ans %= mod;
}
cout << ans << endl;
return 0;
}