ABC 262 E 题解
感觉是一道不是很难想到但还是比较不错的题。
题目要求将k个点染成红色,那么我们不妨首先将所有点视为蓝色,然后一个一个地将红点加进去。
那么就从简单的入手,考虑最初只加入一个红点,那么显然满足要求的边的数量就是这个红色点的度数。
然后考虑再加进去一个红色点,此时满足要求的边的数量还是会加上它的度数,但是显然会出问题:如果这两个红色点之前有边相连,那么它们之间的那条边就是不合法的,我们不应该统计它。
于是此题的重头戏就来了:这条不合法的边我们把它算了两次(加第一个点和第二个点的时候都统计了它),但是,我们把这两次减掉,不影响合法边数量的奇偶性。
所以就直接不用管它了。
再继续往里面加红色点也是同样的道理,每条边只要不合法就说明它连接了两个红色点,那么我们会把它统计两次,但实际上不影响奇偶性,所以可以直接不管。
于是此题就变得很简单了:从图中选出k个点使得度数之和为偶数。
然后我们考虑把所有点按照度数的奇偶性分类统计数量,然后度数为偶数的点加进去对总数的奇偶性没有任何影响,所以可以直接在度数为奇数的点中选出偶数个,其余的选择度数为偶数的点,两种分别求组合数然后用乘法原理统计起来就能得到答案了。
//MrcFrst_LRY
#include<bits/stdc++.h>
using namespace std;
#define il inline
#define re register
#define int long long
const int N=200200,mod=998244353;
int n,ans,m,k,d[N],cnt[2],inv[N],invfac[N],fac[N];
inline int read(){
re int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*f;
}
il int C(int n,int m){
if(n<m)return 0;
return fac[n]*invfac[m]%mod*invfac[n-m]%mod;
}//组合数
il void get_inv(){
fac[0]=invfac[0]=inv[1]=invfac[1]=fac[1]=1;
for(re int i=2;i<=n;i++){
inv[i]=inv[mod%i]*(mod-mod/i)%mod;
fac[i]=fac[i-1]*i%mod;
invfac[i]=invfac[i-1]*inv[i]%mod;
}
}//为计算组合数预处理逆元
signed main(){
n=read(),m=read(),k=read();
for(re int i=1;i<=m;i++){
int u=read(),v=read();
d[u]++,d[v]++;//统计度数
}
get_inv();
for(re int i=1;i<=n;i++)cnt[d[i]&1]++;//按度数的奇偶性将点分类统计数量
for(re int i=0;i<=k;i+=2)
(ans+=(C(cnt[1],i)*C(cnt[0],k-i))%mod)%=mod;
cout<<ans;
return 0;
}