[Luogu] CF949E Binary Cards
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;
}