Codeforces Round #613 (Div. 2)D(贪心,分治)
构造两颗深度为30的字典树(根节点分别是0和1),结点只有0和1,从根节点向下DFS,贪心取答案。
1 #define HAVE_STRUCT_TIMESPEC 2 #include<bits/stdc++.h> 3 using namespace std; 4 vector<int>a; 5 int dfs(vector<int>b,int x){ 6 if(x<0||b.size()==0)//30位都枚举完毕或当前向量中没有数字就中止 7 return 0; 8 vector<int>c,d; 9 for(int i=0;i<b.size();++i){ 10 if((b[i]>>x)&1) 11 c.push_back(b[i]);//当前位为1的数放进c 12 else 13 d.push_back(b[i]);//当前位为0的数放进d 14 } 15 if(c.size()==0)//b中所有数字当前位都为1,那么可以把题意中X的当前位构造为1(假定这一位是1),异或下来这一位就是0 16 return dfs(d,x-1); 17 else if(d.size()==0)//b中所有数字当前位都为0,那么可以把题意中X的当前位构造为0(假定这一位是0),异或下来这一位就是0 18 return dfs(c,x-1); 19 return (1<<x)+min(dfs(c,x-1),dfs(d,x-1));//b中数字当前位有0也有1,那么题意中X的当前位无论取0还是1,异或下来这一位都会是1,所以这一位异或的贡献为(1<<x),然后加上c和d两组数当中更小的贡献 20 } 21 int main(){ 22 ios::sync_with_stdio(false); 23 cin.tie(NULL); 24 cout.tie(NULL); 25 int n; 26 cin>>n; 27 for(int i=1;i<=n;++i){ 28 int temp; 29 cin>>temp; 30 a.push_back(temp); 31 } 32 int ans=dfs(a,29);//二进制下从高位枚举,如果高位已经注定产生分支,那么就可以取低位贡献的最小值(低位贡献再大,合计也不会比高位某一位贡献大,所以取两个分支中较小的即可,较大的那一分支可以让它的高位异或为0,这样它低位的贡献也不会比另一分支要大。另一分支就可以贪心使得低位的贡献最小) 33 //(可以构造一棵深度为30,分支只有0或1的字典树) 34 cout<<ans; 35 return 0; 36 }
保持热爱 不懈努力
不试试看怎么知道会失败呢(划掉)
世上无难事 只要肯放弃(划掉)