[Luogu] CF949E Binary Cards

(Link)

Description

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

((n,|A_i|leq 100000,kleq20))

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)要去重;其二,要限制搜索深度。注意到(kle20),考虑极端情况,即不断的(+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
", 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;
}
原文地址:https://www.cnblogs.com/andysj/p/14002156.html