https://codeforces.com/problemset/problem/1417/E
正解:
从二进制最高位开始算,不断分开分开就是答案了。
每一位存下来按照01分开,贪心做事情,具体看代码吧,挺简单
#include<iostream> #include<vector> using namespace std; typedef long long ll; const int maxn = 3e5+11; vector<int>chal; ll dp[100][10]; int list[maxn]; ll ans = 0; int dfs(vector<int>ins ,int dep){ if(dep < 0 ) return 0; if(ins.size() == 0) return 0; vector<int>cns; int cnt1=0,cnt0=0; for(int i=ins.size()-1;i>=0;i--){ int x = (ins[i] >> dep)&1; if(x == 1){ cnt1++; dp[dep][1] += cnt0; } else{ cnt0++; dp[dep][0] += cnt1; } } for(int i = 0;i<ins.size();i++){ int x = (ins[i] >> dep)&1; if(x == 0){ cns.push_back(ins[i]); } } dfs(cns,dep-1); cns.clear(); for(int i = 0;i<ins.size();i++){ int x = (ins[i] >> dep)&1; if(x == 1){ cns.push_back(ins[i]); } } dfs(cns,dep-1); cns.clear(); } int main(){ int n; scanf("%d",&n); for(int i=0;i<n;i++){ int x; scanf("%d",&x); chal.push_back(x); } dfs(chal,30); ll cns = 0; ll ans =0 ; for(int i=30;i>=0;i--){ if(dp[i][0] < dp[i][1]){ cns += (1<<i); } ans += min(dp[i][0],dp[i][1]); } printf("%lld %lld",ans,cns); return 0; }
还有一种做法是我第一次写的时候盲猜的,利用线段树动态开点暴力算异或对是不是变多了,。。。结果给T了,如果n是1e5说不定可以呢。。。
#include<iostream> #include<cstring> using namespace std; const int maxn = 3e5+1111; typedef long long ll; struct Node{ int l,r,ans; }tree[maxn*40]; int list[maxn]; int cnt = 2; int update(int & node,int be,int en,int i,int val){ if(node == 0) node = ++cnt; int mid = be + en >> 1; if(be == en ){ tree[node].ans += val; return 0; } if(i <= mid) update(tree[node].l,be,mid,i,val); else update(tree[node].r,mid+1,en,i,val); int l = tree[node].l; int r = tree[node].r; tree[node].ans = tree[l].ans + tree[r].ans; } int ask(int node,int be,int en,int LL,int RR){ if(node == 0) return 0; int mid = be + en >> 1; if( LL <= be && en <= RR){ return tree[node].ans; } int val1 = 0,val2 = 0; if(LL <= mid) val1 = ask(tree[node].l,be,mid,LL,RR); if(RR > mid) val2 = ask(tree[node].r,mid+1,en,LL,RR); return val1 + val2; } int init(){ for(int i=0;i<=cnt;i++){ tree[i].l = tree[i].r = tree[i].ans = 0; } cnt = 2; return 0; } int main(){ int root = 1; int n; scanf("%d",&n); for(int i=0;i<n;i++){ scanf("%d",&list[i]); } cnt = 2; ll ans = 1e17; int nn = 1e9+11; ll cns = 0; for(int i = 30;i>=0;i--){ int x = 1<<i; ll a = 0; ll b = 0; for(int j=n-1;j>=0;j--){ if(list[j] == 0){ update(root,0,nn,0,1); continue; } a += ask(root,0,nn,0,list[j]-1); update(root,0,nn,list[j],1); } for(int j=n-1;j>=0;j--){ update(root,0,nn,list[j],-1); } for(int j=n-1;j>=0;j--){ list[j] ^= x; if(list[j] == 0){ update(root,0,nn,0,1); continue; } b += ask(root,0,nn,0,list[j]-1); update(root,0,nn,list[j],1); } for(int j=n-1;j>=0;j--){ update(root,0,nn,list[j],-1); } if(a <= b){ for(int j=0;j<n;j++){ list[j] ^= x; } } else{ cns += x; } a = min(a,b); ans = min(a,ans); } printf("%lld %lld ",ans,cns); return 0; } ?