AtcoderABC262 E Red and Blue Graph

这篇博客介绍了如何解决一个关于图论的问题,即给定一个简单无向图,染色每个顶点为红色或蓝色,要求有特定数量的红色顶点,并且连接不同颜色顶点的边数为偶数。博主通过分析发现,关键在于确保边的连接方式使得不同颜色的边数为偶数,然后利用组合数学计算满足条件的染色方案数。代码中展示了利用C++实现的解决方案,时间复杂度为O(n+m)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

AtcoderABC262

题目描述

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) (1iM) 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 2N2105
  • 1 ≤ M ≤ 2 ∗ 1 0 5 1\leq M\leq 2*10^5 1M2105
  • 0 ≤ K ≤ N 0\leq K\leq N 0KN
  • 1 ≤ U i < V i ≤ N ( 1 ≤ i ≤ M ) 1\leq U_i<V_i\leq N(1\leq i\leq M) 1Ui<ViN(1iM)
  • ( 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 iScnti=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 k2t 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值