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 }
posted @ 2020-01-12 11:43  sewage  阅读(154)  评论(0编辑  收藏  举报