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;
}
?