Placing Medals on a Binary Tree Gym - 101158G (The 2016 Asia Regional Contest, Tsukuba)
题意: 现在有一颗满二叉树,现在有n个金牌,每个金牌上刻着一个数字x,代表这个金牌要放在深度为x的节点上,放金牌有一个规则就是这个节点到根节点的路上不能经过其他节点,从前向后放金牌,能放就放下输出Yes,放不下就跳过放下一个输出No.
做法:首先我们可以将这个满二叉树想象成二进制,每次加一个节点,就是加1/y,y=2^x,也就相当于在二进制的这一位上加了一个1,当什么时候这棵树加满了就不行了,或者允许加的值比我的值小,也就是我这一位的前年没有0的存在了,那么也是不可以的。
为什么场上没有写呢:首先是想到了二进制的,但是觉得每次更新需要向前更新很远,可能会超时,就没有写。
为什么现在写了呢:稍微优化了一点就是,我们判断某一个点是否可行的时候,不是从1号直接判断到x号找零了,西施我保存了一个最前面的零的位置,也就是这个值前面全部都是1,这样的话,我每次只需要从后面的一段寻找就可以了,还有一个就是,层数低于这个值的,我们已经知道前面全都是1了,可以直接跳出。 当已经放满1了的时候所有值都放不进去了,也是跳出,例如放了一个第一层的,两个第二层的,那么之后无论放什么都放不进去,因为已经满了。
代码如下:
#include<stdio.h> #include<iostream> #include<string.h> #include<algorithm> #include<map> using namespace std; map<int,int>mp; ///记录每一层现在的值是多少 1代表不能再放了 0代表还可以放 int n; int num; ///输入的值 奖牌上的数值 int maxx; ///记录了现在哪一层被放满了 这样的话 在它上面就不能放了 在它下面还可以放 于是需要保存最大值 int main() { scanf("%d" , &n); mp[0] = 0; ///初始值一个都还没有放 maxx = 0; ///题目给出金牌不可以放在根节点上 while( n-- ) { scanf("%d" , &num); if(num<=maxx || mp[0]==1) { ///如果这个金牌要放在满层的上面 是放不下的 或者现在整棵树都放满了 也是放不下的了 printf("No\n"); continue; } bool flag = false; ///判断这个值能否放下 如果在它之前包括它自己含有可以放的层 那么它就可以放下 for(int i=maxx+1; i<=num; i++) { if(mp[i]==0) { flag = true; break; } maxx++; ///前面连续的都是0 就可以更新maxx } if(!flag) { printf("No\n"); continue; ///如果在它之前放不下 那么此时就放不下了 } int i = num; mp[i]++; while(i>=0) { if(mp[i]==2) { mp[i]=0; mp[i-1]+=1; i--; } else { break; } } printf("Yes\n"); // for(int i=0; i<=5; i++) // { // printf("%d " , mp[i]); // } // printf("\n%d...\n" , maxx); } return 0; }