题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5573
这个题……规律暂时还找不到,先贡献两发TLE的代码吧,一个dfs一个状压枚举。

1 #include <algorithm>
2 #include <iostream>
3 #include <iomanip>
4 #include <cstring>
5 #include <climits>
6 #include <complex>
7 #include <fstream>
8 #include <cassert>
9 #include <cstdio>
10 #include <bitset>
11 #include <vector>
12 #include <deque>
13 #include <queue>
14 #include <stack>
15 #include <ctime>
16 #include <set>
17 #include <map>
18 #include <cmath>
19
20 using namespace std;
21
22 typedef long long ll;
23 const int maxn = 66;
24
25 ll n, k;
26 ll path[maxn][3];
27 int pcnt;
28 //1 + 0 -
29 bool exflag;
30 void dfs(ll cur, ll lv, ll id) {
31 if(exflag) return;
32 if(cur == n && lv == k) {
33 for(ll i = 0; i < pcnt; i++) {
34 printf("%I64d %c\n", path[i][0], path[i][1] == 1 ? '+' : '-');
35 }
36 exflag = 1;
37 return;
38 }
39 if(cur != n && lv == k) return;
40
41 path[pcnt][0] = id;
42 path[pcnt++][1] = 1;
43 dfs(cur+id ,lv+1, id*2);
44 pcnt--;
45
46 path[pcnt][0] = id;
47 path[pcnt++][1] = 1;
48 dfs(cur+id ,lv+1, id*2+1);
49 pcnt--;
50
51 path[pcnt][0] = id;
52 path[pcnt++][1] = 0;
53 dfs(cur-id ,lv+1, id*2);
54 pcnt--;
55
56 path[pcnt][0] = id;
57 path[pcnt++][1] = 0;
58 dfs(cur-id ,lv+1, id*2+1);
59 pcnt--;
60 }
61
62 int main() {
63 // freopen("in", "r", stdin);
64 int T, _ = 1;
65 scanf("%d", &T);
66 while(T--) {
67 scanf("%I64d %I64d", &n, &k);
68 pcnt = 0; exflag = 0;
69 printf("Case #%d:\n", _++);
70 dfs(0, 0, 1);
71 }
72 return 0;
73 }

#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <ctime>
#include <set>
#include <map>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn = 66;
ll n, k;
ll f[maxn];
ll ans[maxn];
bool sub[maxn];
void init() {
f[0] = 1;
for(int i = 1; i < maxn; i++) {
f[i] = f[i-1] * 2;
}
}
int main() {
// freopen("in", "r", stdin);
int T, _ = 1;
init();
scanf("%d", &T);
while(T--) {
scanf("%I64d %I64d", &n, &k);
for(int i = 1; i <= k; i++)
ans[i] = f[i-1];
if(n % 2 == 0) ans[k]++;
ll nn = 1 << k;
bool exflag = 0;
for(ll i = 1; i < nn; i++) {
if(exflag) break;
ll cur = 0;
memset(sub, 0, sizeof(sub));
for(ll j = 1; j <= k; j++) {
if((1 << j) & i) {
sub[j] = 1;
cur -= ans[j];
}
else cur += ans[j];
}
if(cur == n) exflag = 1;
}
printf("Case #%d:\n", _++);
for(ll i = 1; i <= k; i++) {
printf("%I64d ", ans[i]);
if(sub[i]) printf("-\n");
else printf("+\n");
}
}
return 0;
}
这个题想了很多天,想明白了其实还蛮简单的。
题目给了一棵满二叉树,按照层次遍历从左到右挨个编号1 2 3....问蛤蛤从根节点向下走,走到一个点可以加上当前节点编号也可以删掉当前节点编号。问走k层能否恰好续够n。
题目中给了一个条件:N≤2^K≤2^60
因为读题坑掉了没看到这个条件,浪费了很多时间在例如n=10 k=3的情况上。这种情况在我的搜索中是完全有结果的,但是实际上这个情况不会在题目中出现,因为8<10。
这样就好办了,我们考虑任何一个十进制数都可以表示为二进制,这个二进制表示了某一位上是否要加上对应的2的幂次。
(以上皆为口胡+脑补,正常题解在下面)
N<=2^k意味着我们总能找到第k+1个节点,使得N小于k+1节点的数值。既然如此,我们贪心地选取最左边的一条链。这样,最左边那个点必然是整层最小的。对于本题目而言,总有2^(k+1)-1≥n。
由于最左侧的链均为2的幂次,我们以前的知识中一定有这样一条规律:2^(k)-1=∑i(1,k-1)2^i。表达不清楚,举个例子:32-1=1+2+4+8+16。
我们假设整条长度为k链都是加的,那它的总和就是2^(k+1)-1,我们现在知道要求的n,那我们不需要的那部分的值为2^(k+1)-1-n。
假设这个值为x,那x也总是能表达为一个二进制数,我们只需要在这个链子上找到可以表示x的二进制数的位置,把它们标记为'-'即可。
1 #include <algorithm>
2 #include <iostream>
3 #include <iomanip>
4 #include <cstring>
5 #include <climits>
6 #include <complex>
7 #include <fstream>
8 #include <cassert>
9 #include <cstdio>
10 #include <bitset>
11 #include <vector>
12 #include <deque>
13 #include <queue>
14 #include <stack>
15 #include <ctime>
16 #include <set>
17 #include <map>
18 #include <cmath>
19
20 using namespace std;
21
22 typedef long long ll;
23 const int maxn = 66;
24 ll n, k;
25 ll f[maxn];
26 ll ans[maxn];
27 bool sub[maxn];
28
29 void init() {
30 f[0] = 1;
31 for(int i = 1; i < maxn; i++) {
32 f[i] = f[i-1] * 2;
33 }
34 }
35
36 int main() {
37 // freopen("in", "r", stdin);
38 int T, _ = 1;
39 init();
40 scanf("%d", &T);
41 while(T--) {
42 scanf("%I64d %I64d", &n, &k);
43 memset(sub, 0, sizeof(sub));
44 for(int i = 1; i <= k; i++)
45 ans[i] = f[i-1];
46 ll remain = f[k] - n - 1;
47 if(n % 2 == 0) {
48 ans[k]++;
49 remain++;
50 }
51 remain >>= 1;
52 int cnt = 1;
53 while(remain) {
54 if(remain % 2 == 1) sub[cnt] = 1;
55 remain >>= 1;
56 cnt++;
57 }
58 printf("Case #%d:\n", _++);
59 for(int i = 1; i <= k; i++) {
60 printf("%I64d ", ans[i]);
61 sub[i] ? printf("-\n") : printf("+\n");
62 }
63 }
64 return 0;
65 }
来源:https://www.cnblogs.com/kirai/p/5430063.html
