连这个场上过了70+人的题都不会,脑子可能没救了。
先只考虑一个
D
D
D的情况,我们将距离为
D
\sqrt D
D的点连边,可以证明得到的是一个二分图。具体的,设
D
=
2
2
k
⋅
p
(
p
m
o
d
4
≠
0
)
D=2^{2k}\cdot p(p \mod 4 \neq 0 )
D=22k⋅p(pmod4=0),根据简单的数论知识,所有距离为
D
D
D的点对都可以写成
(
2
k
⋅
u
,
2
k
⋅
v
)
(2^k\cdot u,2^k \cdot v)
(2k⋅u,2k⋅v)的形式,其中
u
2
+
v
2
=
p
u^2+v^2=p
u2+v2=p,于是我们可以只考虑
m
o
d
2
k
\bmod 2^k
mod2k的等价类。注意当
p
m
o
d
4
≡
3
p \mod 4 \equiv 3
pmod4≡3的时候不存在合法点对,若
p
m
o
d
4
≡
1
p \bmod 4 \equiv 1
pmod4≡1,
u
u
u和
v
v
v一奇一偶,按
u
+
v
u+v
u+v的奇偶性染色即可,若
p
m
o
d
4
≡
2
p \bmod 4 \equiv 2
pmod4≡2,
u
u
u和
v
v
v均为奇数,按
u
u
u的奇偶性染色即可。
那么问题变为我们得到了两张二分图,要求取出一个大小为
V
4
\frac{V}{4}
4V的点集,使得在两张图上均为独立集。给两张图分别二染色后,得到四个集合,取其中大小最大的一个显然就行了。
时间复杂度
O
(
n
2
)
\mathcal O(n^2)
O(n2)。
#include <bits/stdc++.h>
using namespace std;
void col(int n,int m,bool p[][605]) {
int d=0;
while (m%(1<<(2*(d+1)))==0) d++;
d=(1<<d);
int v=(m/(d*d))%4;
if (v==0||v==3) return;
if (v==1) {
for(int i=0;i<n;i++)
for(int j=0;j<n;j++) p[i][j]=(((i/d)+(j/d))&1);
}
else {
for(int i=0;i<n;i++)
for(int j=0;j<n;j++) p[i][j]=((i/d)&1);
}
}
bool f[605][605],g[605][605];
int main() {
int n,D1,D2;
scanf("%d%d%d",&n,&D1,&D2);
col(n<<1,D1,f);
col(n<<1,D2,g);
int sz[2][2]={0};
for(int i=0;i<(n<<1);i++)
for(int j=0;j<(n<<1);j++) sz[f[i][j]][g[i][j]]++;
int id1=0,id2=0;
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
if (sz[i][j]>sz[id1][id2]) {
id1=i;
id2=j;
}
int cnt=0;
for(int i=0;i<(n<<1);i++) {
for(int j=0;j<(n<<1);j++)
if (f[i][j]==id1&&g[i][j]==id2) {
printf("%d %d\n",i,j);
cnt++;
if (cnt>=n*n) break;
}
if (cnt>=n*n) break;
}
return 0;
}