【CF949E】Binary Cards
题目
题目链接:https://codeforces.com/problemset/problem/949/E
给出 \(n\) 个需要表示的数,你需要用最少的 \(2^k\) 或 \(-2^k\),使得能拼出所有需要表示的数。输出方案。
\(n,|a_i|\leq 10^5\)。
思路
首先 \(2^k\) 与 \(-2^k\) 中最多选一个。因为选两个 \(2^k\) 不如选 \(2^k\) 和 \(2^{k+1}\);选 \(2^k\) 和 \(-2^k\) 不如选 \(2^{k+1}\) 和 \(-2^k\)。
从低位往高位依次考虑。如果这一位中存在二进制下为 \(1\) 的数,那么必然会选,否则必然不选。
直接枚举所有情况跑是 \(O(nA)\) 的。其中 \(A\) 是值域。观察到处理完第 \(k\) 位后,剩余的所有数 \(\bmod 2^k\) 都应该为 \(0\)。也就是每选一个数,剩余的不同的数的数量就会减半。
那么每次操作完后都去重一次就好了。
时间复杂度 \(O(n\log A)\)。
代码
#include <bits/stdc++.h>
using namespace std;
const int N=100010,LG=18;
int n,m,a[LG+1][N],b[LG+1],c[LG+1];
void solve(int dep,int n,int cnt)
{
if (cnt>=m || dep>LG) return;
if (n==1 && !a[dep][1])
{
memcpy(b,c,sizeof(b)); m=cnt;
return;
}
bool flag=0;
for (int i=1;i<=n;i++)
if (a[dep][i]&1) { flag=1; break; }
if (!flag)
{
for (int i=1;i<=n;i++)
a[dep+1][i]=(a[dep][i]>>1);
solve(dep+1,n,cnt);
}
else
{
for (int i=1;i<=n;i++)
a[dep+1][i]=((a[dep][i]-(a[dep][i]&1))>>1);
int n1=unique(a[dep+1]+1,a[dep+1]+1+n)-a[dep+1]-1;
c[cnt+1]=(1<<dep);
solve(dep+1,n1,cnt+1);
for (int i=1;i<=n;i++)
a[dep+1][i]=((a[dep][i]+(a[dep][i]&1))>>1);
n1=unique(a[dep+1]+1,a[dep+1]+1+n)-a[dep+1]-1;
c[cnt+1]=-(1<<dep);
solve(dep+1,n1,cnt+1);
}
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&a[0][i]);
sort(a[0]+1,a[0]+1+n);
n=unique(a[0]+1,a[0]+1+n)-a[0]-1;
m=1e9;
solve(0,n,0);
cout<<m<<"\n";
for (int i=1;i<=m;i++)
cout<<b[i]<<" ";
return 0;
}