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
",anslen);
for(int i=1;i<=anslen;i++)printf("%d ",ans[i]);
return 0;
}