AGC025D

题目大意:给定一个(2n imes 2n)的平面,在上面取(n imes n)个整点,使得任意两点之间距离( eq sqrt{D1},sqrt{D2})

题目链接:D - Choosing Points


题解:我们先考虑只有(D1)限制的情况,我们将所有距离为(sqrt{D1})的整点连上边,会发现这是一张二分图。证明如下:

考虑将棋盘黑白染色,如果(D1)为奇数,那么黑点和黑点之间不可能连边,白点和白点之间也不可能连边,所以容易证明。

如果(D1)为偶数,黑点之间会互相连边,白点亦是如此,那么将坐标缩小为原来的(frac{1}{sqrt{2}}),然后(D1 div 2)转换为子问题。

所以按照(D1)的限制黑白染色,然后在按照(D2)的限制红蓝染色,根据染色结果将所有的分为 4 类,由于鸽巢原理,一定有至少一类的大小是大于(n imes n)的,所以直接输出即可。

代码:

#include <cstdio>
#include <cstring>
const int Maxn=600;
const int D[4][2]={{1,1},{1,-1},{-1,1},{-1,-1}};
int n,d[2];
int step[2][2][Maxn*Maxn+5];
int len[2];
int num[5];
int col[2][Maxn+5][Maxn+5];
void dfs(int k,int x,int y,int c){
	if(x<1||y<1||x>n||y>n||col[k][x][y]!=-1){
		return;
	}
	col[k][x][y]=c;
	for(int i=1;i<=len[k];i++){
		for(int j=0;j<4;j++){
			dfs(k,x+D[j][0]*step[k][0][i],y+D[j][1]*step[k][1][i],c^1);
		}
	}
}
int main(){
	scanf("%d%d%d",&n,&d[0],&d[1]);
	n<<=1;
	for(int k=0;k<2;k++){
		for(int i=0;i<=n;i++){
			for(int j=0;j<=n;j++){
				if(i*i+j*j==d[k]){
					step[k][0][++len[k]]=i;
					step[k][1][len[k]]=j;
				}
			}
		}
	}
	memset(col,-1,sizeof col);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			dfs(0,i,j,0);
			dfs(1,i,j,0);
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			num[col[1][i][j]<<1|col[0][i][j]]++;
		}
	}
	int tmp;
	for(int i=0;i<4;i++){
		if(num[i]>=(n*n>>2)){
			tmp=i;
		}
	}
	int sz=0;
	for(int i=1;i<=n&&(sz<(n*n>>2));i++){
		for(int j=1;j<=n&&(sz<(n*n>>2));j++){
			if((col[1][i][j]<<1|col[0][i][j])==tmp){
				sz++;
				printf("%d %d
",i-1,j-1);
			}
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/withhope/p/13366651.html