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;
}