发现题解取都是四染色, 发一个二染色的方法.
考虑对格子黑白染色, 坐标和为偶数的染为黑色. 这里我们先假设黑白色都有.
如果所有点分为黑白两组, 满足组间的边为黄色, 组内的边为蓝色, 那么黄色的边平方一定是奇数, 蓝色边的平方一定是偶数, 满足题目条件.
那么我们直接输出即可.
如果只存在一种颜色的点, 假设只存在黑点, 如果只有白点可以全部下移一格转为全为黑点.
现在我们把所有点的坐标由 ( x , y ) (x,y) (x,y) 变为 ( x + y 2 , x − y 2 ) (\frac{x+y}2,\frac{x−y}2) (2x+y,2x−y) , 即进行旋转, 因为全都是黑点那么不会出现小数, 那么如果这时候分为了黑白点就可以由之前的方法解决, 如果还是只有一种颜色就继续递归旋转
现在证明递归的次数为 O ( l o g A ) O(logA) O(logA)次, 其中 A 为值域大小.
我们发现旋转一次一个点到原点的距离的平方除以了二, 但是一个点永远不会变成原点, 且一直是整点, 所以最多会旋转 O ( l o g A ) O(logA) O(logA) 次.
代码
#include <bits/stdc++.h>
#define il inline
#define _for(i, a, b) for (int i = (a); i <= (b); ++i)
#define _fore(i, u) for (int i = hd[u], v; v = tg[i], i; i = nx[i])
using namespace std;
struct {
template <typename T>
il operator T() {
T x = 0, f = 1;
char c = getchar();
while (!isdigit(c)) (c == '-') && (f = -1), c = getchar();
while (isdigit(c)) x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return f * x;
}
} gi;
const int N = 1e3 + 5;
int n, x[N], y[N];
int s[N], ts;
int main() {
n = gi;
for (int i = 1; i <= n; ++i) x[i] = gi, y[i] = gi;
while (1) {
int _a0 = 1, _a1 = 1;
for (int i = 1; i <= n; ++i) _a0 &= !((x[i] + y[i]) & 1), _a1 &= (x[i] + y[i]) & 1;
if (!_a0 && !_a1) {
for (int i = 1; i <= n; ++i)
if ((x[i] + y[i]) & 1) s[++ts] = i;
break;
}
if (_a1)
for (int i = 1; i <= n; ++i) x[i]--;
for (int i = 1, x0, y0; i <= n; ++i) x0 = x[i], y0 = y[i], x[i] = (x0 + y0) >> 1, y[i] = (x0 - y0) >> 1;
}
printf("%d\n", ts);
for (int i = 1; i <= ts; ++i) printf("%d ", s[i]);
return 0;
}