题目描述
You are given a simple undirected graph with N N N vertices and M M M edges. The vertices are numbered 1 , 2 , … , N 1,2,\dots,N 1,2,…,N, and the i i i-th ( 1 ≤ i ≤ M ) (1\leq i\leq M) (1≤i≤M) edge connects Vertices U i U_i Ui and V i V_i Vi.
There are 2 N 2^N 2N ways to paint each vertex red or blue. Find the number, modulo 998244353 998244353 998244353, of such ways that satisfy all of the following conditions:
- There are exactly K K K vertices painted red.
- There is an even number of edges connecting vertices painted in different colors.
Sample Input 1
4 4 2
1 2
1 3
2 3
3 4
Sample Output 1
2
Sample Input 2
10 10 3
1 2
2 4
1 5
3 6
3 9
4 10
7 8
9 10
5 9
3 4
Sample Output 2
64
- 2 ≤ N ≤ 2 ∗ 1 0 5 2\leq N\leq 2*10^5 2≤N≤2∗105
- 1 ≤ M ≤ 2 ∗ 1 0 5 1\leq M\leq 2*10^5 1≤M≤2∗105
- 0 ≤ K ≤ N 0\leq K\leq N 0≤K≤N
- 1 ≤ U i < V i ≤ N ( 1 ≤ i ≤ M ) 1\leq U_i<V_i\leq N(1\leq i\leq M) 1≤Ui<Vi≤N(1≤i≤M)
- ( U i , V i ) ≠ ( U j , V j ) ( i ≠ j ) (U_i,V_i)\neq(U_j,V_j)(i\neq j) (Ui,Vi)=(Uj,Vj)(i=j)
- All values in input are integers.
题目大意
给你一个 n n n个顶点 m m m条边的简单无向图,第 i i i条边连接 U i , V i U_i,V_i Ui,Vi。有 2 n 2^n 2n种方式,将每个顶点染成红色或蓝色。求满足一下条件的方案数,模998244353后的值。
- 有 K K K个点染成红色
- 有偶数条边连接的是不同色的两个顶点
题解
看完题面之后本以为是一道需要 O ( n 2 ) O(n^2) O(n2)甚至 O ( n 3 ) O(n^3) O(n3)来完成的图论题,但看了数据范围,就知道时间复杂度大概是 O ( n ) O(n) O(n)或 O ( n l o g n ) O(nlogn) O(nlogn)。
我们可以分析一下这个图,这个图有若干条红-蓝的边,红-红的边和蓝-蓝的边。我们需要红-蓝的边为偶数个,怎么办呢?
设红-蓝边有 a a a条,红-红边有 b b b条。设 c n t i cnt_i cnti表示有一个顶点为 i i i的边的条数,选中的 K K K个顶点组成集合 S S S,则
∑ i ∈ S c n t i = a + 2 b \sum\limits_{i\in S}cnt_i=a+2b i∈S∑cnti=a+2b
每条红-蓝边被算了一次,红-红边被算了两次。
这时,我们惊奇地发现, a + 2 b a+2b a+2b和 a a a是同奇同偶的。所以,只要满足 a + 2 b a+2b a+2b是偶数,则 a a a一定是偶数。也就是说,我们要取 K K K个 i i i,使 ∑ c n t i \sum cnt_i ∑cnti为偶数
到这里,这道题就很简单了。选 2 t 2t 2t个 c n t cnt cnt值为奇数的 i i i,再选 k − 2 t k-2t k−2t个 c n t cnt cnt值为偶数的 i i i。枚举 t t t,用组合数计算即可。
总时间复杂度为 O ( n + m ) O(n+m) O(n+m)
code
#include<bits/stdc++.h>
using namespace std;
int n,m,k,x,y,cnt[200005],v[2];
long long ans=0,jc[200005],ny[200005];
long long mod=998244353;
long long mi(long long t,long long v){
if(v==0) return 1;
long long re=mi(t,v/2);
re=re*re%mod;
if(v&1) re=re*t%mod;
return re;
}
long long C(int x,int y){
if(x<y) return 0;
return jc[x]*ny[y]%mod*ny[x-y]%mod;
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
jc[0]=1;
for(int i=1;i<=n;i++){
jc[i]=jc[i-1]*i%mod;
}
ny[n]=mi(jc[n],mod-2);
for(int i=n-1;i>=0;i--){
ny[i]=ny[i+1]*(i+1)%mod;
}
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
++cnt[x];++cnt[y];
}
for(int i=1;i<=n;i++){
++v[cnt[i]%2];
}
for(int i=0;i<=k;i+=2){
ans=(ans+C(v[1],i)*C(v[0],k-i)%mod)%mod;
}
printf("%lld",ans);
return 0;
}