发现题解取都是四染色, 发一个二染色的方法.
考虑对格子黑白染色, 坐标和为偶数的染为黑色. 这里我们先假设黑白色都有.
如果所有点分为黑白两组, 满足组间的边为黄色, 组内的边为蓝色, 那么黄色的边平方一定是奇数, 蓝色边的平方一定是偶数, 满足题目条件.
那么我们直接输出即可.
如果只存在一种颜色的点, 假设只存在黑点, 如果只有白点可以全部下移一格转为全为黑点.
现在我们把所有点的坐标由 (x,y) 变为 ((x+y)/2,(x-y)/2) , 即旋转 45°, 因为全都是黑点那么不会出现小数, 那么如果这时候分为了黑白点就可以由之前的方法解决, 如果还是只有一种颜色就继续递归旋转
现在证明递归的次数为 O(logA) 次, 其中 A 为值域大小.
我们发现旋转一次一个点到原点的距离的平方除以了二, 但是一个点永远不会变成原点, 且一直是整点, 所以最多会旋转 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; }