Loading

AtCoder-abc262_e Red and Blue Graph

Red and Blue Graph

思维 + 组合数

从点上想,一直找不到突破口,考虑从边的角度开始想

如果一条边两个端点都是红点,则说明这个边消耗红点的度数为 \(2\)

如果一条边有一个端点是红点,则消耗红点度数为 \(1\)

我们可以从这里开始突破,假设红色点的总度数为 \(D\),两个端点都是红色的边数为 \(R\),两个端点不同色的边数为 \(G\)

则有:\(D = 2 * R + G\)

由于题目限定 \(G\) 一定是个偶数,因此 \(D\) 也必然是个偶数

因此只用考虑奇数度数的点,如何分配 \(K\) 个红色的点

每次考虑奇数的点都是偶数个

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
const int maxn = 2e5 + 10;
vector<int>gra[maxn];
ll init[maxn];

ll qpow(ll x, ll n)
{
    ll ans = 1;
    while(n)
    {
        if(n & 1) ans = ans * x % mod;
        n >>= 1;
        x = x * x % mod;
    }
    return ans % mod;
}

ll calc(ll up, ll down)
{
    ll a = init[down];
    ll b = init[down - up] * init[up] % mod;
    return a * qpow(b, mod - 2) % mod;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n, m, k;
    cin >> n >> m >> k;
    init[0] = 1;
    for(int i=1; i<=n; i++) init[i] = init[i-1] * i % mod;
    for(int i=0; i<m; i++)
    {
        int a, b;
        cin >> a >> b;
        gra[a].push_back(b);
        gra[b].push_back(a);
    }
    int odd = 0, even = 0;
    for(int i=1; i<=n; i++)
    {
        if(gra[i].size() & 1) odd++;
        else even++;
    }
    ll ans = 0;
    int s = max(0, k - even);
    if(s & 1) s++;
    for(int i=s; i<=min(odd, k); i+=2)
        ans = (ans + calc(i, odd) * calc(k - i, even)) % mod;
    cout << ans << endl;
    return 0;
}
posted @ 2022-08-05 20:43  dgsvygd  阅读(69)  评论(0编辑  收藏  举报