把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

CF85E Guard Towers

题面传送门
感觉完全没有黑题难度啊。
首先最大值最小就想到二分答案。二分后转化成判定性问题。
然后我们将两两曼哈顿距离大于\(mid\)的点连边,我们只需要判断是否是二分图即可。
这个东西如果真的建边来空间复杂度很大所以直接隐式建边即可。
然后第二个问统计方案,可以发现如果在一个联通块内有两种情况,那么统计联通块个数然后直接\(2^{cnt}\)即可。
时间复杂度\(O(n^2logn)\)
code:

#include <vector>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<algorithm>
#include<bitset>
#include<set>
#include<map>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define l(x) x<<1
#define r(x) x<<1|1
#define re register
#define ll long long
#define db long double
#define N 5000
#define eps (1e-14)
#define mod 1000000007
#define U unsigned
using namespace std;
int n,x[N+5],y[N+5],col[N+5],l,r,mid,cnt=1,fl[N+5],flag;
I int dis(int a,int b){return abs(x[a]-x[b])+abs(y[a]-y[b]);}
I void dfs(int x,int w,int mid){
	if(!flag) return;if(col[x]){col[x]!=w&&(flag=0);return;}col[x]=w;
	for(int i=1;i<=n;i++)if(dis(x,i)>mid)dfs(i,w*-1,mid);
}
I int check(int mid){
	memset(col,0,sizeof(col));flag=1;for(int i=1;i<=n;i++) !col[i]&&(dfs(i,1,mid),0);return flag;
}
I void find(int x,int mid){
	if(fl[x]) return;fl[x]=1;for(int i=1;i<=n;i++)if(dis(x,i)>mid)find(i,mid);
}
int main(){
	freopen("1.in","r",stdin);
	re int i;scanf("%d",&n);for(i=1;i<=n;i++) scanf("%d%d",&x[i],&y[i]),l=max(l,x[i]),r=max(r,y[i]);r+=l+2;l=-1;
	while(l+1<r) mid=l+r>>1,(check(mid)?r:l)=mid;printf("%d\n",r);for(i=1;i<=n;i++) !fl[i]&&(find(i,r),cnt=cnt*2%mod);printf("%d\n",cnt);
}
posted @ 2021-06-04 22:24  275307894a  阅读(41)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end