CF73D FreeDiv

先抛开操作 \(1\) 不谈, 考虑操作 \(2\) 会不会使图联通,因为显然操作 \(2\) 是一个非常强的操作。
容易发现我们可以随意连边,直到把所有点全用上,那样不会更劣,而且一定会尽量减少联通块个数。
那么只用操作 \(2\) 就使图联通的合法条件就是
\(\Sigma_i min(a_i,k)\) \(\geqslant\) \(2(d-1)\)
然后贪心,每次不合法的时候选择 \(min(a_i,k)\) 最小的两个 \(a_i\) 合并即可。

核心trick: 可以将所有部分一起考虑,如果一个一个考虑有时反而落入下乘
代码

#include<bits/stdc++.h>
#define RG register
#define LL long long
#define U(x, y, z) for(RG int x = y; x <= z; ++x)
#define D(x, y, z) for(RG int x = y; x >= z; --x)
using namespace std;
template <typename T> void read(T &n){ bool f = 1; char ch = getchar(); n = 0; for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = 0; for (; isdigit(ch); ch = getchar()) n = (n << 1) + (n << 3) + (ch ^ 48); if (f == 0) n = -n;}
inline char Getchar(){ char ch; for (ch = getchar(); !isalpha(ch); ch = getchar()); return ch;}
template <typename T> inline void write(T n){ char ch[60]; bool f = 1; int cnt = 0; if (n < 0) f = 0, n = -n; do{ch[++cnt] = char(n % 10 + 48); n /= 10; }while(n); if (f == 0) putchar('-'); for (; cnt; cnt--) putchar(ch[cnt]);}
template <typename T> inline void writeln(T n){write(n); putchar('\n');}
template <typename T> inline void writesp(T n){write(n); putchar(' ');}
template <typename T> inline void chkmin(T &x, T y){x = x < y ? x : y;}
template <typename T> inline void chkmax(T &x, T y){x = x > y ? x : y;}
template <typename T> inline T Min(T x, T y){return x < y ? x : y;}
template <typename T> inline T Max(T x, T y){return x > y ? x : y;}
inline void readstr(string &s) { s = ""; static char c = getchar(); while (isspace(c)) c = getchar(); while (!isspace(c)) s = s + c, c = getchar();}
inline void FO(string s){freopen((s + ".in").c_str(), "r", stdin); freopen((s + ".out").c_str(), "w", stdout);}

const int N = 1e6 + 10;
int n, m, k;
int fa[N];
inline int findf(int x) {return fa[x] == x ? x : fa[x] = findf(fa[x]);}
int d, cnt[N];

int main(){
	//FO("");
	read(n), read(m), read(k);
	U(i, 1, n) fa[i] = i;
	U(i, 1, m) {
		int u, v;
		read(u), read(v);
		u = findf(u), v = findf(v);
		if (u == v) continue ;
		else fa[u] = v; 
	}

	U(i, 1, n) {
		int t = findf(i);
		if (cnt[t] == 0) ++d;
		++cnt[t];
	}

	int t = 0;
	priority_queue<int, vector<int>, greater<int> > q;
	U(i, 1, n) {
		t += min(cnt[i], k);
		if (cnt[i] != 0) q.push(cnt[i]);
	}
	d = 2 * (d - 1);
	int ans = 0;
	while (d > t) {
		++ans; int u = q.top(); q.pop(); int v = q.top(); q.pop();
		t -= min(u, k) + min(v, k) - min(u + v, k); q.push(u + v);
		d -= 2;
	} 

	writeln(ans);
	return 0;
}
posted @ 2022-10-19 22:29  Southern_Way  阅读(24)  评论(0)    收藏  举报