1. 程式人生 > 其它 >【CF949E】Binary Cards

【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;
}