题意
给出n个需要表示的数,你需要用最少的
2k
2
k
或
−2k
−
2
k
,使得能拼出所有需要表示的数。输出方案。
n,|Ai|<=100000
n
,
|
A
i
|
<=
100000
分析
不难发现
2k
2
k
和
−2k
−
2
k
里面最多只要选一个,因为选两个
2k
2
k
一定没有选
2k
2
k
和
2k+1
2
k
+
1
优秀,选
2k
2
k
和
−2k
−
2
k
一定没有选
2k
2
k
和
−2k+1
−
2
k
+
1
优秀。
那么我们可以考虑缩小规模:
当所有数都是偶数的时候,把每个数除以2然后递归下去。
否则的话就有选1和-1两种情况,只要枚举每一种情况然后递归下去就好了。
在递归到每一层的时候去一下重,那么第i层的数的数量就不超过
Ai2i
A
i
2
i
。
于是总的复杂度就是O(nlogn)。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=200005;
const int inf=1000000000;
int n,a[N],f[20][N],ans,tot[20],A[20],top,stack[20];
void solve(int dep,int step)
{
if (dep==19) return;
sort(f[dep]+1,f[dep]+tot[dep]+1);
tot[dep]=unique(f[dep]+1,f[dep]+tot[dep]+1)-f[dep]-1;
int s1=0,s0=0;
for (int i=1;i<=tot[dep];i++)
if (f[dep][i]!=0&&f[dep][i]%2==0) s0++;
else if (f[dep][i]%2!=0) s1++;
if (!s0&&!s1)
{
if (step<ans)
{
ans=step;
for (int i=1;i<=step;i++) A[i]=stack[i];
}
return;
}
if (!s1)
{
tot[dep+1]=0;
for (int i=1;i<=tot[dep];i++)
if (f[dep][i]/2!=0) f[dep+1][++tot[dep+1]]=f[dep][i]/2;
solve(dep+1,step);
}
else
{
tot[dep+1]=0;stack[++top]=1<<dep;
for (int i=1;i<=tot[dep];i++)
if (f[dep][i]%2==0&&f[dep][i]/2!=0) f[dep+1][++tot[dep+1]]=f[dep][i]/2;
else if (f[dep][i]%2!=0) f[dep+1][++tot[dep+1]]=(f[dep][i]-1)/2;
solve(dep+1,step+1);top--;
tot[dep+1]=0;stack[++top]=-(1<<dep);
for (int i=1;i<=tot[dep];i++)
if (f[dep][i]%2==0&&f[dep][i]/2!=0) f[dep+1][++tot[dep+1]]=f[dep][i]/2;
else if (f[dep][i]%2!=0) f[dep+1][++tot[dep+1]]=(f[dep][i]+1)/2;
solve(dep+1,step+1);top--;
}
}
int main()
{
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;
tot[0]=n;
for (int i=1;i<=n;i++) f[0][i]=a[i];
ans=20;solve(0,0);
printf("%d\n",ans);
for (int i=1;i<=ans;i++) printf("%d ",A[i]);
return 0;
}