CodeForces Goodbye2019 E.Divide Points (构造)

题目:传送门

思路及代码参考了这位大佬的博客 点此跳转

现将点分为四类 :(0表示偶数,1表示奇数)

  1. (0,0)
  2. (1,1)
  3. (0,1)
  4. (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;
}
原文地址:https://www.cnblogs.com/DeepJay/p/12215030.html