题目:传送门
思路及代码参考了这位大佬的博客 点此跳转
现将点分为四类 :(0表示偶数,1表示奇数)
- (0,0)
- (1,1)
- (0,1)
- (1,0)
如果有至少一个点属于 3或4 ,则可以将所有点分为 {1,2} 和 {3,4};
这样划分,集合内部距离平方为偶,集合之间的距离平方为奇数,满足题意;
如果没有点属于 3或4 ,则将所有点分为 {1} 和 {2} ;
这样划分 1:( 2 * x,2 * y ) ; 2: ( 2 * z + 1,2 * k + 1 ) ;
那么集合内部是 x1-x2 与 y1-y2 都是偶数
集合之间 则都是奇数;
平方和相加,集合内部的距离 为两个偶数之和
平方和相加,集合之间的距离 为 两个奇数之和(奇数的平方还是奇数)
故满足题意;
如果所有点都是第一类的,那么我对所有坐标除以2,这样操作是对距离的相对关系是没有任何影响的,知道出现了非第一类点,就可以开始分类了(不存在奇数除以2的情况);
因为我们是围绕第一类进行构造,为了保证一定会有第一类点,我们将所有坐标的进行平移,代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
typedef pair<LL,LL> pLL;
const int N=1e6+5;
const int inf=0x3f3f3f3f;
const LL INF=1LL<<50;
#define ls (i<<1)
#define rs (i<<1|1)
#define fi first
#define se second
#define mk make_pair
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define debug puts("...")
LL read()
{
LL x=0,t=1;
char ch=getchar();
while(!isdigit(ch)){ if(ch=='-')t=-1; ch=getchar(); }
while(isdigit(ch)){ x=10*x+ch-'0'; ch=getchar(); }
return x*t;
}
int x[N],y[N];
vector<int> a,b;
int main()
{
int n=read();
for(int i=1;i<=n;i++)
x[i]=read(),y[i]=read();
for(int i=n;i;i--) x[i]-=x[1],y[i]-=y[1]; ///保证一定有(偶,偶)这一种情况
while(1)
{
for(int i=1;i<=n;i++)
if(x[i]%2||y[i]%2) goto out;
for(int i=1;i<=n;i++)
x[i]>>=1,y[i]>>=1;
}out:;
for(int i=1;i<=n;i++)
{
//printf("x=%d , y=%d
",x[i],y[i]);
if(x[i]%2&&y[i]%2) b.pb(i);
else if(x[i]%2==0&&y[i]%2==0) a.pb(i);
}
if(a.size()+b.size()==n)
{
printf("%d
",a.size());
for(int i=0;i<a.size();i++)
printf("%d ",a[i]);
}
else
{
printf("%d
",a.size()+b.size());
for(int i=0;i<a.size();i++)
printf("%d ",a[i]);
for(int i=0;i<b.size();i++)
printf("%d ",b[i]);
}
return 0;
}