Codeforces 949E Binary Cards

Description

给出一个长度为 \(n\) 的数组,求使得用最少数量的 \(2^k\)\(-2^k\) 的数,使得数组中的每一个元素都可以被你选出的 \(2\) 的次幂表示
题面

Solution

注意到两个性质:
1.一个数不会用两次,举个例子:用两个 \(2\),不如用 \(2,4\) 范围广
2.一个数不会既用 \(2^k\) 又用 \(-2^k\),显然用 \(-2^k,2^{k+1}\) 或者 \(2^k,-2^{k+1}\) 更优

这样就可以依次考虑每一位了:
如果所有的数都不含有这一位,那么就直接把所有的数除以 \(2\)
如果存在数含有这一位,那么用 \(-2^k\) 或者 \(2^k\) 把含有这一位的数都给去掉,然后再把所有的数除以 \(2\)
对于第二种情况我们直接搜索一下就好了

这样复杂度有些问题,但是我们把数去重之后,第 \(k\) 层的数就最多只有 \(\frac{max(A[i])}{2^{k}}\)
复杂度就变成了分治的复杂度了

#include <bits/stdc++.h>
using namespace std;
const int N=100010;
int a[N],b[21][N],top=0,st[N],ans[N],anslen=N;
inline void dfs(int t,int n){
	if(t>20 || top>=anslen)return ;
	if(n==1 && !b[t][1]){
		if(top<anslen){
			anslen=top;
			for(int i=1;i<=top;i++)ans[i]=st[i];
		}
		return ;
	}
	bool flag=1;
	for(int i=1;i<=n;i++)if(b[t][i]&1){flag=0;break;}
	if(flag){
		for(int i=1;i<=n;i++)b[t+1][i]=b[t][i]>>1;
		n=unique(b[t+1]+1,b[t+1]+n+1)-b[t+1]-1;
		dfs(t+1,n);
		return ;
	}
	for(int w=-1;w<=1;w+=2){
		for(int i=1;i<=n;i++)
			if(b[t][i]&1)b[t+1][i]=(b[t][i]+w)>>1;
			else b[t+1][i]=b[t][i]>>1;
		st[++top]=-w*(1<<t);
		int tmp=unique(b[t+1]+1,b[t+1]+n+1)-b[t+1]-1;
		dfs(t+1,tmp);
		top--;
	}
}
int main()
{
	freopen("pp.in","r",stdin);
	freopen("pp.out","w",stdout);
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	sort(a+1,a+n+1);
	n=unique(a+1,a+n+1)-a-1;
	for(int i=1;i<=n;i++)b[0][i]=a[i];
	dfs(0,n);
	printf("%d\n",anslen);
	for(int i=1;i<=anslen;i++)printf("%d ",ans[i]);
	return 0;
}

posted @ 2018-07-14 22:01  PIPIBoss  阅读(203)  评论(0编辑  收藏  举报