标签:
给你一棵完全二叉树,初始能量为0,根节点编号为1(也就是说最左边那条路上节点的编号分别是2^0,2^1,2^2…2^(h-1))。从根节点开始往下走k-1步,走到每个节点选择加上或减去这个节点的编号,问走完这k个节点时能量恰好为n的方案。Special Judge.
在队友的提醒下(TAT我真是讨厌鹰语)看明白了数据范围,很明显是一个考二进制性质的题。于是一上手我先把样例改成了走最左路线的情况。样例出的蛮良心,一个奇数一个偶数,刚好对应两条路线:一直走左儿子或者走k-2个左儿子最后一个走右儿子。
路线分析完了,现在解决判断加减的问题。很容易发现-1变到+1差2,-2变到+2差4,于是这个问题还是深♂入的玩二进制,把所有情况可以归结到n=1+tmp*2(偶数再+1)。n=1的情况非常好搞,就是一路减下来最后一步加,非常基础的数学问题。然后我们就可以根据tmp的二进制表示推出答案辣!
什么?你推不出?跟我往下看↓【推得出的童鞋可以跳过】
上文已经提到tmp=(n-1)/2。为什么除2呢,因为一加一减造成的差值是翻倍的。当然这个情况下n为奇数,偶数的话请先自行减一。
现在把它写成k-1位的二进制表达。因为n是正数,所以最后一个节点必然是+,不用考虑。以3 5为例,tmp=1,所以写出来了0001.这就表明在2^0的时候需要把-翻转成+,其他不变。输出结果:1+ 2- 4- 8- 16+ 是不是很神奇~因为写成二进制表示的每一位就对应了2^i即题中说的节点编号,所以这样构造是正确的。
现在证它可以满足所有情况。因为n是不小于1且不大于2的k次幂的,所以最大值最小值均可以满足要求。k-1位二进制的全排列共有2^(k-1)种,对应奇偶两种不同的结尾选择后共2^k种结果,与n∈[1,2^k]形成一一对应的关系。
此题到此结束。
下面附上代码:
1 #include <stdio.h> 2 typedef long long LL; 3 LL bit2[66]; 4 int bit[66]; 5 void init() 6 { 7 bit2[0] = 1; 8 for (int i=1; i<63; i++) 9 bit2[i] = bit2[i-1] * 2; 10 } 11 int main() 12 { 13 int t,n,k,cas=1; 14 init(); 15 scanf("%d",&t); 16 while (t--) { 17 bool flag = false; //标记n是否为奇数 18 scanf("%d%d",&n,&k); //大概这样,我记不清n和k的顺序了 19 if (n & 1) flag = true; 20 else n--; 21 int tmp = (n - 1) / 2; 22 for (int i=0; i<k-1; i++) { //对应k-1位二进制表达的翻转 23 bit[i] = tmp & 1; 24 tmp >>= 1; 25 } 26 for (int i=0; i<k-1; i++) { 27 printf("%lld ",bit2[i]); 28 puts(bit[i] ? "+" : "-"); 29 } 30 if (flag) printf("%lld +\n",bit2[k-1]); 31 else printf("%lld -\n",bit2[k-1]+1); 32 } 33 return 0; 34 }
//话说我看到有人说二分,并不太懂…这不是个纯纯的构造么…在此求教…
标签:
原文地址:http://www.cnblogs.com/honeycat/p/4995177.html