显然,直接暴力枚举是不可能的。
考虑将点按横纵坐标奇偶性分组,记 \(S_{i,j}=\{t|x_t\equiv i\pmod{2},y_t\equiv j\pmod{2}\}(i,j\in[0,1])\),说白了就是横坐标为偶数、纵坐标为偶数;横坐标为偶数、纵坐标为奇数;横坐标为奇数、纵坐标为偶数;横坐标为奇数、纵坐标为奇数的点集。
然后考虑以下算法:
-
若 \(S_{0,0},S_{1,1}\) 以及 \(S_{0,1},S_{1,0}\) 中至少各有一个集合非空,那么我们令 \(A=S_{0,0}\cup S_{1,1},B=S_{1,0}\cup S_{0,1}\) 即可,因为对于 \(S_{0,0},S_{1,1}\) 中任意两点,它们距离的平方要么模 \(4\) 余 \(0\),要么模 \(4\) 余 \(2\),\(S_{0,1},S_{1,0}\) 也同理;而对于 \(S_{0,0},S_{1,1}\) 与 \(S_{0,1},S_{1,0}\) 之间的点,距离的平方模 \(4\) 余 \(1\),符合题目要求。
-
若 \(S_{0,0}\) 以及 \(S_{1,1}\) 均非空,那么我们令 \(A=S_{0,0},B=S_{1,1}\) 即可。因为对于 \(S_{0,0}\) 中的任意点它们距离的平方模 \(4\) 余 \(0\),\(S_{1,1}\) 也同理;对于 \(S_{0,0}\) 与 \(S_{1,1}\) 之间的点它们距离的平方模 \(4\) 余 \(2\)。满足两两不同的条件。
-
若 \(S_{1,0}\) 以及 \(S_{1,0}\) 均非空,类比 \(S_{0,0}\) 以及 \(S_{1,1}\) 非空的情况即可。
-
若以上条件均不满足,即 \(S_{0,0},S_{0,1},S_{1,0},S_{1,1}\) 中恰有一个非空,那么我们令所有点横纵坐标除以 \(2\),再重复以上操作即可,因为我们总能找到一个时刻使得 \(S_{0,0},S_{0,1},S_{1,0},S_{1,1}\) 不止一个非空。
这样即可通过此题。
你可能会疑惑我为什么要为这道 *2300 的题专门写篇题解,题目本身虽然简单,但也能从中学到一个解决构造题的技巧:观察题目中奇偶性。有不少构造题都是以奇偶性为突破口解决的,当然有时候解构造题的关键不仅仅局限于奇偶性,包括题目中给定的一些特殊的条件等,总而言之解决构造题的技巧说白了只有一点,那就是观察题目中的性质。u1s1 我构造题做不出来大概也就是因为我不具备猜结论的能力罢
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned int u32;
typedef unsigned long long u64;
namespace fastio{
#define FILE_SIZE 1<<23
char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
inline void putc(char x){(*p3++=x);}
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc(x%10^48);}
template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);}
void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
}
const int MAXN=1e3;
int n,x[MAXN+5],y[MAXN+5];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d%d",&x[i],&y[i]);
while(1){
static int cnt[2][2];memset(cnt,0,sizeof(cnt));
for(int i=1;i<=n;i++) cnt[x[i]&1][y[i]&1]++;
if(cnt[0][0]+cnt[1][1]>0&&cnt[0][1]+cnt[1][0]>0){
vector<int> ans;
for(int i=1;i<=n;i++) if((x[i]&1)^(y[i]&1)) ans.pb(i);
printf("%d\n",ans.size());
for(int i=0;i<ans.size();i++) printf("%d ",ans[i]);
printf("\n");return 0;
} else if(cnt[0][0]>0&&cnt[1][1]>0||cnt[0][1]>0&&cnt[1][0]>0){
vector<int> ans;
for(int i=1;i<=n;i++) if(x[i]&1) ans.pb(i);
printf("%d\n",ans.size());
for(int i=0;i<ans.size();i++) printf("%d ",ans[i]);
printf("\n");return 0;
}
for(int i=1;i<=n;i++) x[i]>>=1,y[i]>>=1;
}
return 0;
}