考虑如何快速求出一堆二元组xor某数之后求差的和,因为a−b=∑i=02i(abi−bbi)(abi表示a二进制第
因为题目求的是差的绝对值,而两数只有在他们最高的不同位被xor时才会改变大小关系,故可以按照二元组的最高的不同位将其分为O(logn)种。这样,只需要O(log2n)就可以计算出一个数组xor某数后的instability。
考虑通过枚举x来求出结果,无脑枚举的复杂度是
#include<algorithm>
#include<iostream>
#include<climits>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long ll;
#define clr(a) memset(a,0,sizeof(a))
const ll md=1000000007;
int ar[100000],n,sr[20][20][2][2];ll xr[1<<20],tr[1<<20],xsr[20][20][2][2];
int _cl(int x){
int i=19,j=1<<19;for(;i>=0&&!(x&j);j>>=1,--i);
return i;
};
ll _cl(int d,int k,int v,bool fg){
int i,j;ll r;for(r=0,i=0;i<2;++i)for(j=0;j<2;++j){
r+=sr[d][k][i][j]*(fg?(j^v)-(i^v):(i^v)-(j^v));
}
return (ll)r*(1<<k);
};
void _cl(int d,int v){
int i,j,t,a,b;ll r;
for(i=19,j=1<<19;!(v&j);j>>=1,--i);r=xr[v^j];
if(d==i)for(xr[v]=0,j=0;j<20;++j)xr[v]+=xsr[d][j][v&(1<<j)?1:0][1];
else{
r-=xsr[d][i][0][v&(1<<d)?1:0];r+=xsr[d][i][1][v&(1<<d)?1:0];xr[v]=r;
}
};
void __cl(int d){
int i,j,t,a,b;for(clr(sr),i=1;i<n;++i){
t=_cl(ar[i]^ar[i-1]);if(t<0)continue;
a=ar[i],b=ar[i-1];if(a<b)swap(a,b);
for(j=0;j<20;++j)sr[t][j][a&(1<<j)?1:0][b&(1<<j)?1:0]++;
}
for(i=0;i<20;++i)for(j=0;j<20;++j)for(t=0;t<2;++t)
xsr[i][j][t][0]=_cl(i,j,t,0),xsr[i][j][t][1]=_cl(i,j,t,1);
for(clr(tr),i=0;i<20;++i){
for(xr[0]=0,j=0;j<20;++j)xr[0]+=xsr[i][j][0][0];tr[0]+=xr[0];
for(j=1;j<=d;++j){_cl(i,j);tr[j]+=xr[j];}
}
};
void cl(){
int i,j,a,d;ll t,r;scanf("%d",&n);
for(i=0;i<n;scanf("%d",&ar[i++]));
for(d=ar[0],i=1;i<=n;d=max(d,ar[i++]));__cl(d);
for(r=LLONG_MAX,i=0;i<=d;++i)if(tr[i]<r)
r=tr[i],a=i;
printf("%d %I64d\n",a,r);
};
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int t;scanf("%d",&t);
while(t--)cl();
return 0;
};