题意:首先给你一个集合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-num[id]); for(int i=1;i<=n;i++) if(cnt[i]!=id) printf("%lld ",a[i]); return 0; }