Codeforces 1220 D - Alex and Julian

题意: 给定一个长度为 n n n的序列 B B B,对于任意的整数,当 ∣ i − j ∣ |i-j| ij属于 B B B时,点 i i i和点 j j j之间会连一条边,问至少删除 B B B中多少元素可以使得所有整数形成的图是一个二分图

题解: 二分图的性质:一个图为二分图当且仅当图中不存在奇数环。
那么借助这个性质,我们先考虑将当前符合条件的整数,即两个整数差的绝对值在 B B B中存在时,将其连上一条边。那么对于存在于 B B B中的两个点 a a a b b b,可以看成两者分别从 0 0 0开始后,以每次走 a a a步和 b b b步往前走,那么两者第一次相遇就是在 l c m ( a , b ) lcm(a,b) lcm(a,b)处(第 2 2 2次,第 3 3 3 ⋯ \cdots 都可以看成以前一次相遇处为起点再往后走 l c m ( a , b ) lcm(a,b) lcm(a,b)的总步数)。
此时以步幅 a a a和步幅 b b b前进分别走了 l c m ( a , b ) a \frac{lcm(a,b)}{a} alcm(a,b) l c m ( a , b ) b \frac{lcm(a,b)}{b} blcm(a,b)次,化简下得到:以步幅 a a a走了 b g c d ( a , b ) \frac{b}{gcd(a,b)} gcd(a,b)b次,以步幅 b b b走了 a g c d ( a , b ) \frac{a}{gcd(a,b)} gcd(a,b)a步。

由于不能形成奇数环,故要使得 b g c d ( a , b ) + a g c d ( a , b ) ≡ 0 ( m o d   2 ) \frac{b}{gcd(a,b)}+\frac{a}{gcd(a,b)}\equiv0(mod\ 2) gcd(a,b)b+gcd(a,b)a0(mod 2)

那么问题就转换成了两种情况:
1.   b g c d ( a , b ) 1. \ \frac{b}{gcd(a,b)} 1. gcd(a,b)b a g c d ( a , b ) \frac{a}{gcd(a,b)} gcd(a,b)a都为奇数

2.   b g c d ( a , b ) 2. \ \frac{b}{gcd(a,b)} 2. gcd(a,b)b a g c d ( a , b ) \frac{a}{gcd(a,b)} gcd(a,b)a一奇一偶

∗   b g c d ( a , b ) * \ \frac{b}{gcd(a,b)}  gcd(a,b)b a g c d ( a , b ) \frac{a}{gcd(a,b)} gcd(a,b)a都为偶数是不可能的,
因为都为偶数就说明两者分母还可以继续除 2 2 2,那么分母就不是 g c d gcd gcd

我们要求的是什么样的情况下使得图为二分图,即使得图中不存在奇数环,那么一奇一偶显然不成立。那么要求的便是两者都为奇数的情况。
由于要尽量少删除数,将 B B B中所有数写成 2 k ∗ v 2^{k}*v 2kv v v v是一个奇数。那么只有当两个数的 k k k相等时,
  b g c d ( a , b ) \ \frac{b}{gcd(a,b)}  gcd(a,b)b a g c d ( a , b ) \frac{a}{gcd(a,b)} gcd(a,b)a才会都为奇数。
所以保留下来的即写成 2 k ∗ v 2^k*v 2kv后, 2 0 ∼ 63 2^{0\sim63} 2063数最多的幂。


代码:

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 2e5 + 10;
ll q[N], n;
vector<ll> ans[64]; 
int main()
{
	scanf("%d", &n);
	for(int i = 1; i <= n; i++) {
		scanf("%lld", &q[i]);
		int cnt = 0; ll x = q[i];
		while(x % 2 == 0) cnt++, x /= 2;
		ans[cnt].push_back(q[i]);
	}
	
	int Ma = 0;
	for(int i = 0; i < 64; i++)
		if((int)ans[i].size() > (int)ans[Ma].size()) Ma = i;
	
	printf("%d\n", n - (int)ans[Ma].size());
	for(int i = 0; i < 64; i++) { 
		if(i == Ma) continue;
		int len = (int)ans[i].size();
		for(int j = 0; j < len; j++)
			printf("%lld ", ans[i][j]);
	} 
	
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值