题目链接

题意:首先给你一个集合B,定义一个图是由整数集合为定点,若i,j为整数,且 abs(i - j) 在集合 B 之中,那么图中存在一条连接 i,j 的无向边。问至少去掉 B 中多少个元素才能使这张图为一个二分图。

其实我不清楚这道题到底算不算数论,但肯定不是图论,只用到了判定二分图的基本方法:不存在奇环。

如何让这个图不存在奇环?

我们考虑起点为 0,如果 B 中存在整数 a, 那么 0 与 a 之间有一条边,a 与 2 * a 之间也有一条边,如果这时 B 中还存在着整数 2 * a,那么这时 0,a,2 * a 这三个点就形成了奇环。

考虑到这里,我们发现,如果我们已经选中了一个数 a,那么要不存在奇环,只有将 a / 2(a % 2 == 0) , a / 4(a % 4 == 0)…… ,a * 2 ,a * 4,…… 全部删去。

但这样思考却很难求出答案,那就只有换一个思考方向,想一想如果选中了 a,那么哪些数可以保留,不难发现,只有和 a 同次数(不停的除以 2,直到无法除尽或等于 0 为止,这样操作的次数)的数才能和 a 一起保留。因为这样的话,这些数中就不会出现翻倍的关系。

那么代码就很简单了

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int n,num[100],cnt[200010];
LL a[200010];

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    for(int i=1;i<=n;i++)
    {
        LL temp=a[i];
        while(temp&&temp%2==0)
        {
            cnt[i]++;
            temp/=2;
        }
        num[cnt[i]]++;
    }
    int id=0;
    for(int i=1;i<=63;i++) if(num[i]>num[id]) id=i;
    printf("%d\n",n-num[id]);
    for(int i=1;i<=n;i++) if(cnt[i]!=id) printf("%lld ",a[i]);
    return 0;
}
02-13 19:26