您的位置:首页 > 其它

HDU 5573 Binary Tree 2015上海现场赛B题

2015-12-10 14:31 489 查看
题目大意:

有一个深度无限的完全二叉树,每个节点有一个标号:根节点标号为1,之后对于标号为x的节点,左孩子标号为2x,右孩子标号为2x+1(其实就是zkw线段树的标号规则)。现在从根节点开始向下走k步(根节点也算一步),每到一个节点可以选择加上或减去节点的标号,求最终结果为N的走法,其中N>=1且题目保证有解。

思路:

首先,我们用二进制数mask表示取数的方法,1表示+,0表示-,顺序从左向右,最右一位表示最后一次取数的方法;用pos表示最后到达节点的标号。这样就可以唯一确定一种走法,且很容易写出计算最终结果的函数f(mask,pos)。如k=3,mask=5,pos=7表示的路径为1 +,3 -,7 +,f(5,7)=5。

为方便表述再定义F(mask,x,pos,y)为mask右x位确定,pos左y位确定后,f的取值范围

经过观察很容易得到以下结论

最后一个节点取法一定为+,即mask&1=1

在k确定,后x步取法确定(即mask的右x位确定),前y步走法(即pos前y位确定)的情况下,f取值连续,且当所有未确定位全部置0时取得最小值

根据上述条件,只需依次确定mask和pos的值就可以得到答案

初状态mask最右位必然为1,pos最左位必然为1外其它位均未确定,根据题目限制N必包含在取值范围中,即F(1,1,1 << k,1)包含N

1.确定mask

从右向左依次确定mask,比如当前已确定前i位(mask其它位全部置0),则

F(mask,i,1<< k,1)最小值为f(mask,1<< k)

检查f(mask^(1<< i),1<< k))是否大于N,如果不大于N,则F(mask^(1<< i),i+1,1<< k,0)必包含N,否则F(mask,i+1,1<< k,0)必包含N

2.确定pos

此时mask已确定

从左向右依次确定pos,比如已确定前i位(pos其它位全部置0),则

F(mask,k,pos,i)最小值为f(mask,pos)

检查f(mask,pos^(1<<(k-1-i)))是否大于N,如果不大于N,则F(mask,k,pos^(1<<(k-1-i)),i+1)必包含N,否则F(mask,k,pos,i+1)必包含N

最后根据mask和pos打印路径即可

求解f(mask,pos)函数的复杂度为k,最终的复杂度O(k^2)

另外先pos再确定mask也是可行的

代码:

Problem : 5573 ( Binary Tree ) Judge Status : Accepted

RunId : 15788211 Language : G++ Author : qsqx

#include <iostream>
#include <stdio.h>
#include <queue>
#include <map>
8dcc
;
#include <algorithm>
#include <string.h>
#define ll long long
#define forn(i,n) for(int i=0;i<(n);++i)
#define rep(i,n) for(int i=1;i<=(n);++i)
#define pii pair<int,int>
#define mp(x,y) make_pair((x),(y))
using namespace std;
ll f(ll mask,ll pos) {
ll res = 0;
while (pos) {
if (mask & 1)
res += pos;
else
res -= pos;
pos >>= 1;
mask >>= 1;
}
return res;
}
vector <pair<ll , char> >res;
void print(ll mask,ll pos) {
res.clear();
while (pos) {
if (mask & 1)
res.push_back(mp(pos, '+'));
else
res.push_back(mp(pos, '-'));
pos >>= 1;
mask >>= 1;
}
int len = res.size();
for (int i = len - 1; i >= 0; --i) {
printf("%lld %c\n", res[i].first, res[i].second);
}
}
void solve() {
ll n;
int k;
cin >> n >> k;
ll mask = 1;
for (int t = 1; t <k;++t) {
if (f(mask | (1LL << t), 1LL << (k - 1))<=n) {
mask |= (1LL << t);
}
}
ll pos = 1LL << (k - 1);
for (int t = k - 2; t >= 0; --t) {
if (f(mask, pos | (1LL << t)) <= n)
pos |= (1LL << t);
}

print(mask, pos);
}
int main(){
//freopen("abc.txt", "r", stdin);
int T;
cin >> T;
rep(t, T) {
printf("Case #%d:\n",t);
solve();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: