题解 CF85E 【Guard Towers】

题目传送门


算法分析:二分答案+二分图判定

首先分析题目大意。很显然,按照题意将塔分为两组后,同组内没有其他联系,于是我们可以想到二分图基本模型。题设的条件就是要求我们将若干座塔构造成一个二分图。于是将题意简化如下:

求一张二分图,使得每组内两个点之间的曼哈顿距离的最大值最小,并求出符合条件的方案数。

等等,我们应该如何建图?注意到最大值最小,可以尝试用二分答案的方式求解。对答案(曼哈顿距离的最大值的最小值)进行二分,在符合距离的两点间连边,然后采用染色法判定该图是不是二分图,如果是,就记录答案,这样一轮结束后,我们就可以得到第一问的答案。

接下来我们解决第二问。如何求方案数?我们先考虑最普通的二分图,其左部点和右部点可以确定。从样例一可以知道,左部和右部可以互换,因此在这种情况下,一共有两种情况。我们再看下图,下图显然是一个可行的二分图,但是有多个连通块,对于每个连通块都有两种方案,因为连通块内部的左部点和右部点互换对其他连通块并没有影响。记连通块数量为 \(k\) ,那么总方案数就有 \(2^k\) 种,由于 \(k\) 可能较大,用快速幂会比较方便。


细节提示:

注意到 \(n\le 5000\),在极限情况下时空复杂度达到\(n^2\) 级别,尽管可以勉强承受,但是过于浪费,因此不必显式建图,可以在染色的同时寻找符合要求的对象。

上代码:

#include<bits/stdc++.h>
#define F(i,a,b) for(register int i=(a);i<=(b);i++)
using namespace std;
const int N=5005,mod=1e9+7;
int n,col[N],num,ans,cnt;
struct P {
	int x,y;
} a[N];
inline int dis(P a,P b) {//曼哈顿距离 
	return abs(a.x-b.x)+abs(a.y-b.y);
}
long long fc(int x,int y) {//快速幂 
	if(!y)return 1;
	long long pos=fc(x,y>>1)%mod;
	if(y&1)return pos*pos%mod*x%mod;
	return pos*pos%mod;
}
bool dfs(int x,int mi) {
	F(i,1,n){
		if(dis(a[x],a[i])<=mi or i==x)continue;
		if(!col[i]) {
			col[i]=col[x]^1;//染色
			if(!dfs(i,mi))return false;//染色失败,不是二分图
		} else if(col[i]==col[x])return false;//同上 
	}
	return true;
}
inline bool check(int mid) {
	memset(col,0,sizeof(col));//记录颜色 
	num=0;
	F(i,1,n) {
		if(!col[i]) {
			col[i]=2;
			num++;//一次dfs出的显然是一个连通块,num记录连通块数量 
			if(!dfs(i,mid))return false;
		}
	}
	cnt=num;//cnt记录答案的连通块数量 
	return true;
}
int main() {
	scanf("%d",&n);
	F(i,1,n)scanf("%d%d",&a[i].x,&a[i].y);
	int l=0,r=1e4;
	while(l<=r) {//二分答案 
		int mid=l+r>>1;
		check(mid)?r=mid-1,ans=mid:l=mid+1;
	}
	printf("%d\n%lld\n",ans,fc(2,cnt));
	return 0;
}

欢迎交流讨论,请点个赞哦~

AC记录

posted @ 2021-06-23 15:48  Maplisky  阅读(66)  评论(0编辑  收藏  举报