Solution -「多校联训」签到题
阅读原文时间:2023年07月09日阅读:1

\(\mathcal{Description}\)

  Link.

  给定二分图 \(G=(X\cup Y,E)\),求对于边的一个染色 \(f:E\rightarrow\{1,2,\dots,c\}\),最小化每个结点所染颜色数量极差之和。输出这一最小值。

  \(|X|+|Y|,|E|\le10^6\)。

\(\mathcal{Solution}\)

  基于“结论好猜”就能认为这题是签到题吗……

  答案显然有下界 \(\sum_{u}\left[c\not\mid \sum_{v}[(u,v)\in E]\right]\)。由于写一发过掉了大样例,我们尝试证明它必然可取到。

证明

  **引理(对于二分图的 Vizing 定理):** 对于二分图 $G$,$\chi'(G)=\Delta(G)$,其中 $\chi'(G)$ 为 $G$ 的边染色的色数,$\Delta(G)$ 为 $G$ 中结点的最大度数。

  证明: 给出构造。按任意顺序枚举 \((x,y)\in E\),令 \(p\) 为 \(x\) 的邻接边中未染的最小颜色,\(q\) 为 \(y\) 的邻接边中未染的最小颜色。由于 \(\chi'(G)=\Delta(G)\),\(p,q\) 是存在的。

  综上,每条边都能被染色且不出现共色的邻接边。命题得证。 \(\square\)

  尝试将原命题向引理靠拢。令新图 \(G'\) 初始为 \(G\)。依次枚举 \(G'\) 中的结点 \(x\),尝试将其拆点。设 \(x\) 的邻接点集为 \(\operatorname{adj}(x)\),任取它的一个划分 \(S=\{S_1,\cdots,S_k\}\),满足 \(|S_1|=\cdots=|S_{k-1}|=c\),若 \(k>1\),则令 \(V_{G'}\leftarrow V_{G'}\cup\{x_1,\cdots,x_k\}\setminus\{x\}\),且 \(\operatorname{adj}(x_i)\leftarrow S_i\)。注意若 \(x\) 已是拆出的点,那么必然不会导致图的变动,拆点是可完成的。

  此后,发现 \(\Delta(G')\le c\) 且 \(G'\) 依旧是二分图。由引理,\(\chi'(G)=\Delta(G)\),我们取出这样一个染色 \(f\),将拆点合并回原图 \(G\) 且不改变边染色,显然 \(f\) 取到了答案下界。 \(\square\)

  \(\mathcal O(|X|+|Y|+|E|)\) 算一算就好。

/*~Rainybunny~*/

#ifndef RYBY
#pragma GCC optimize( "Ofast" )
#endif

#include <bits/stdc++.h>

#define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
#define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i )

inline char fgc() {
    static char buf[1 << 17], *p = buf, *q = buf;
    return p == q && ( q = buf + fread( p = buf, 1, 1 << 17, stdin ), p == q )
       ? EOF : *p++;
}

inline int rint() {
    int x = 0, s = fgc();
    for ( ; s < '0' || '9' < s; s = fgc() );
    for ( ; '0' <= s && s <= '9'; s = fgc() ) x = x * 10 + ( s ^ '0' );
    return x;
}

const int MAXN = 1e6;
int n, m, k, c, deg[MAXN + 5];

int main() {
    freopen( "qiandao.in", "r", stdin );
    freopen( "qiandao.out", "w", stdout );

    n = rint(), m = rint(), k = rint(), c = rint();
    rep ( i, 1, k ) {
        int u = rint(), v = rint();
        ++deg[u], ++deg[v + n];
    }
    int ans = 0;
    rep ( i, 1, n + m ) ans += !!( deg[i] % c );
    printf( "%d\n", ans );
    return 0;
}

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章