题目
给你n(2<=n<=1e3)个二维坐标(xi,yi)(-1e6<=xi,yi<=1e6),把它们分成两个非空点集A和B,
对于n个点产生的种欧式距离,
若这两个点来自相同的点集,则用黄色标注,否则用蓝色标注,
要求输出点集A的大小及选取方案,
使得不存在欧氏距离相同的不同颜色标注的数
思路来源
官方题解
题解
奇偶讨论,令cnt[0/1][0/1]表示xi%2,yi%2的数量,
①若存在(x+y)%2==0与(x+y)%2==1两集合均非空,则如此划分,
这样相同集合内欧氏距离平方为偶,相异为奇
②若存在同奇同时非空(即00和11),则如此划分
这样相同集合内欧氏距离平方被4整除,相异被4除余2
③若存在同偶同时非空(即01和10),则如此划分
这样相同集合内欧氏距离平方被4整除,相异被4除余2
证明可采用设xi=2ki+1代入的方式
如果均不存在,说明只有一个集合非空,设cnt[a][b]非空,由于01对应了其奇偶
这样(x-a)/2,(y-b)/2均能整除,等比例缩小之后再进行求解
由于两两点不同,在log2e6步内势必会将距离缩小到一个大于等于1的最小值
复杂度O(1e3*log(2e6))
代码
#include<bits/stdc++.h>
using namespace std;
#define pb push_back
typedef long long ll;
const int N=1e3+10,off=1e6;
int n,x[N],y[N],cnt[2][2];
vector<int>ans;
void out(vector<int> &x){
printf("%d\n",(int)x.size());
for(int y:x){
printf("%d ",y);
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d%d",&x[i],&y[i]);
x[i]+=off;y[i]+=off;
}
while(1){
memset(cnt,0,sizeof cnt);
for(int i=1;i<=n;++i){
cnt[x[i]%2][y[i]%2]++;
}
//存在和为偶 和为奇
if(cnt[0][0]+cnt[1][1]>0 && cnt[0][1]+cnt[1][0]>0){
for(int i=1;i<=n;++i){
if((x[i]+y[i])%2){
ans.pb(i);
}
}
out(ans);
break;
}
//存在两奇 或两偶
if(cnt[0][0]+cnt[0][1]>0 && cnt[1][1]+cnt[1][0]>0){
for(int i=1;i<=n;++i){
if(x[i]%2){
ans.pb(i);
}
}
out(ans);
break;
}
//说明只有一种 若cnt[a][b]>0 则(x[i]-a)/2 (y[i]-b)/2恰能整除
//这样递归下去 因为两两不同 且坐标只有2e6 必能在1e3 log2e6步内结束
for(int i=1;i<=n;++i){
x[i]/=2;y[i]/=2;
}
}
return 0;
}