[Luogu] CF949E Binary Cards

\(Link\)

Description

给出\(n\)个需要表示的数,你需要用最少的\(2^k\)\(-2^k\),使得能拼出所有需要表示的数。输出方案。

\((n,|A_i|\leq 100000,k\leq20)\)

Solution

神奇的搜索。

要注意到一个数是最多被选一次的,否则答案一定不优;且不会同时用\(2^k\)\(-2^k\)

直接搜索即可。设集合\(S\)表示要被拼成数的集合,\(f(S)\)为最小代价。

\(1\)表示给\(S\)中所有奇数\(+1\)\((f(S+1))\)\(2\)表示给\(S\)中所有奇数\(-1\)\((f(S-1))\)\(3\)表示给\(S\)中所有数(偶数)\(/2\)\((f(\frac{S}{2}))\)

\(S\)都为偶数时,\(f(S)=f(\frac{S}{2})\),操作序列中加入一个\(3\)

否则\(f(S)=min(f(S-1),f(S+1))+1\),操作序列中加入一个\(1\)\(2\)

\(S\)中只剩下\(0\)时,停止操作。

考虑某个操作序列对应的逆序列,其实就是把所有数拼出来的过程。且可以保证只会产生\(2^k/-2^k\)

然鹅这道搜索远没有这么简单。。

首先是必须要剪枝的。其一,每次操作后,对\(S\)要去重;其二,要限制搜索深度。注意到\(k\le20\),考虑极端情况,即不断的\(+1/-1;/2\),重复\(20\)次,此时最大搜索深度达到最大,为\(40\)

还要注意,\(a\)数组要设两维,分别表示对应深度和数值,就不用回溯了。一定记得不能先令\(b_i=a_i\),回溯时再\(a_i=b_i\),因为随着\(a_i\)不断操作,\(b_i\)也会不断改变,那么\(a_i\)回溯到的值可能就不是原来的了。

Code

#include <bits/stdc++.h>

using namespace std;

int n, t, tt, sz, res = 1e9, a[55][100005], out[100005], cnt[100005], mul[100005], que[1000005];

int read()
{
	int x = 0, fl = 1; char ch = getchar();
	while (ch < '0' || ch > '9') { if (ch == '-') fl = -1; ch = getchar();}
	while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + ch - '0'; ch = getchar();}
	return x * fl;
}

int check(int p, int len)
{
	for (int i = 1; i <= len; i ++ ) if (a[p][i]) return 0;
	return 1;
}

void dfs(int dep, int sum, int len)
{
	if (sum > res || dep > 41) return;
	int now = check(dep, len);
	if (now)
	{
		res = sum;
		for (int i = 1; i <= t; i ++ ) que[i] = cnt[i];
		sz = t;
		return;
 	}
	int fl = 1;
	for (int i = 1; i <= len; i ++ )
		if (a[dep][i] % 2) fl = 0;
	if (fl)
	{
		cnt[ ++ t] = 3;
		for (int i = 1; i <= len; i ++ ) a[dep + 1][i] = a[dep][i] / 2;
		int l0 = unique(a[dep + 1] + 1, a[dep + 1] + len + 1) - a[dep + 1] - 1;
		dfs(dep + 1, sum, l0);
		t -- ;
	}
	else
	{
		cnt[ ++ t] = 1;
		for (int i = 1; i <= len; i ++ ) a[dep + 1][i] = a[dep][i] + ((a[dep][i] & 1) > 0);
		int l0 = unique(a[dep + 1] + 1, a[dep + 1] + len + 1) - a[dep + 1] - 1;
		dfs(dep + 1, sum + 1, l0);
		t -- ;
		cnt[ ++ t] = 2;
		for (int i = 1; i <= len; i ++ ) a[dep + 1][i] = a[dep][i] - ((a[dep][i] & 1) > 0);
		l0 = unique(a[dep + 1] + 1, a[dep + 1] + len + 1) - a[dep + 1] - 1;
		dfs(dep + 1, sum + 1, l0);
		t -- ;
	}
	return;
}

int main()
{
	n = read();
	for (int i = 1; i <= n; i ++ )
		a[0][i] = read();
	sort(a[0] + 1, a[0] + n + 1);
	dfs(0, 0, n);
	printf("%d\n", res);
	for (int i = 1; i <= sz; i ++ )
		mul[i] = mul[i - 1] + (que[i] == 3);
	for (int i = 1; i <= sz; i ++ )
	{
		if (que[i] == 1) out[ ++ tt] = -1 * pow(2, mul[i]);
		else if (que[i] == 2) out[ ++ tt] = pow(2, mul[i]);
	}
	for (int i = 1; i <= tt; i ++ )
		printf("%d ", out[i]);
	puts("");
	return 0;
}
posted @ 2020-11-18 21:08  andysj  阅读(86)  评论(0编辑  收藏  举报