题意:如果你有一个原数列的话你可以对任何一个数字进行操作,令这个数字乘2或者乘2后在加1。现在给你一个目标数列,让你求一个原数列,这个原数列是所有可能的原数列当中最大的一个元素最小的那种。注意原数列和目标数列都必须满足set内元素的性质(即每个元素都不相同),但是在变化的过程中不需要满足这个条件。
分析:原来的贪心思路是每次取出最大的一个元素把它一直除以2,一直这样操作到不能再小为止(再小就重复了),这样操作完每个数字以后就可以了。但是这样的话连最后一组数据都过不了。于是稍稍的改变贪心思路,每次取出最大的数字,除以2,如果没有重复元素的话就结束(也就是说不必一次就把它除到最小)并且放回集合里面,一直这样操作直到最大的数字无法变化为止。这样的贪心思路才是正确的。
具体见代码:
1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 #include <set> 5 using namespace std; 6 const int N = 50000 + 50; 7 8 int a[N],n; 9 10 int main() 11 { 12 set<int> S; 13 scanf("%d",&n); 14 for(int i=1;i<=n;i++) {scanf("%d",a+i);S.insert(a[i]);} 15 16 while(1) 17 { 18 set<int>::iterator it = S.end(); 19 it--; 20 int p = *it; 21 while(S.find(p)!=S.end() && p) 22 { 23 p >>= 1; 24 } 25 if(p==0) break; 26 S.erase(it); 27 S.insert(p); 28 } 29 int first = 0; 30 for(set<int>::iterator it=S.begin();it!=S.end();it++) 31 { 32 if(!first) {first=1;printf("%d",*it);} 33 else printf(" %d",*it); 34 } 35 puts(""); 36 }