题目链接
题意:
给出一个完全二叉树,顺序编号。每一点的权值为其编号。
从根节点开始走,初始总和 sum 为0。
每次可以选择左右儿子中的一个往下走,可以选择让 sum 减去其权值 或者 加上其权值。
输出一条到第 k 层的路径,满足 sum 恰好为 N。
1
≤
N
≤
1
0
9
1 \leq N \leq 10^{9}
1≤N≤109
N
≤
2
K
≤
2
60
N \leq 2^{K} \leq 2^{60}
N≤2K≤260
分析:
应该是完全二叉树的性质,满足一定存在这样的路径。
但是从根节点往下走不好判断左右儿子走哪个,加还是减。
可以从叶节点往上走,只需要判断父节点加还是减。
叶子节点很多,但是从前往后走不了多远就能找到满足的。
贪心搞:从下往上走,一开始碰见的都是比较大的。
如果当前的 sum 小于 n 的话,那么就加上;否则就减去。
到根节点如果正好是 n 的话,那么这条路径就是满足的。
应该是因为这刚好是完全二叉树,所以这样贪心是正确的。
Code:
//https://vjudge.net/problem/HDU-5573
#include<bits/stdc++.h>
using namespace std;
/**/
const int N = 200010, mod = 1e9+7;
int T, n, m;
int a[N], flag;
int path[N];
char f[N];
void dfs(int x, int sum, int flor)
{
path[flor] = x;
if(flor == 0){
if(sum == n) flag = 1;
return;
}
if(flag) return;
if(sum <= n) //没拿之前总和比n小,就拿
{
f[flor] = '+';
dfs(x/2, sum+x, flor-1);
}
else{ //没拿之前总和比n大,不拿
f[flor] = '-';
dfs(x/2, sum-x, flor-1);
}
}
signed main(){
Ios;
cin >> T;
for(int ca = 1; ca <= T; ca ++)
{
int k;
cin >> n >> k;
flag = 0;
for(int i = (1ll<<k-1); i < (1ll<<k); i++)
{
dfs(i, 0, k);
if(flag) break;
}
cout << "Case #" << ca << ":\n";
for(int i=1;i<=k;i++) cout << path[i] << " " << f[i] << "\n";
}
return 0;
}
经验:
题目既然没说有不满足的情况,那就说明一定能满足。
但是在哪个地方满足不知道。
所以要敢于暴力,因为不知道走到哪里就break了。
以后碰见没说 -1 的题要敢于暴力。