CF85E Guard Towers

Fire_Raku發表於2024-05-02

CF85E Guard Towers

二分+二分圖

看到最大值最小,考慮二分。二分距離最大值,限制了某些點對不能分到同一組,明顯的二分圖模型。

用這些限制條件建圖,跑二分圖染色,看是否能分為二分圖即可。

考慮方案數的計算,題目中方案數不同的要求是第一組的集合不同就為不同方案,所以跑完二分圖後,圖分為若干連通塊,連通塊中有若干黑點和白點,可以讓黑點在第一組的集合也可以讓白點在第一組,所以若連通塊個數為 \(x\),那麼方案數就是 \(2^x\)

複雜度 \(O(n^2\log n)\)感覺一點跑不過去啊

#include <iostream>
#include <vector>
#include <cstdio>
#include <cmath>
#include <string>
#include <array>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <algorithm>
#include <cstdlib>
#include <bitset>
#include <string.h>
#define pii std::pair<int, int>
#define fi first
#define se second
#define pb push_back

typedef long long i64;
const i64 iinf = 0x3f3f3f3f, linf = 0x3f3f3f3f3f3f3f3f;
const int N = 5e3 + 10, mod = 1e9 + 7;
int n;
i64 ans, ans2, cnt;
int col[N];
struct node {int x, y;} a[N];
std::vector<int> e[N];
bool dfs(int u, int fa, int co) {
	col[u] = co;
	for(auto v : e[u]) {
		if(v == fa) continue;
		if(col[v] == -1) {
			if(!dfs(v, u, co ^ 1)) return 0;
		} else if(col[u] == col[v]) return 0;
	}
	return 1;
}
int dis(node a, node b) {
	return abs(a.x - b.x) + abs(a.y - b.y);
}
bool check(int x) {
	cnt = 0;
	memset(col, -1, sizeof(col));
	for(int i = 1; i <= n; i++) e[i].clear();
	for(int u = 1; u <= n; u++) {
		for(int v = u + 1; v <= n; v++) {
			if(dis(a[u], a[v]) > x) e[u].pb(v), e[v].pb(u);
		}
	}
	for(int i = 1; i <= n; i++) {
		if(col[i] == -1) {
			cnt++;
			if(!dfs(i, 0, 0)) {
				return 0;
			}
		}
	}
	ans2 = cnt;
	return 1;
}
i64 qpow(i64 a, i64 b) {
	i64 ret = 1;
	while(b) {
		if(b & 1) ret = ret * a % mod;
		a = a * a % mod;
		b >>= 1;
	} 
	return ret;
}
void Solve() {
	std::cin >> n;
	for(int i = 1; i <= n; i++) {
		std::cin >> a[i].x >> a[i].y;
	}
	int l = 0, r = 1e4;
	while(l <= r) {
		int mid = (l + r) >> 1;
		if(check(mid)) r = mid - 1, ans = mid;
		else l = mid + 1;
	}
	std::cout << ans << "\n" << qpow(2, ans2) << "\n";
}
int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
	Solve();

	return 0;
}

相關文章