版权声明:本文为博主原创文章,转载时请注明原文地址=w=,希望对您有所帮助 https://blog.csdn.net/Eirlys_North/article/details/71157900
题意:给定n个数,每次任选两个数,将这两个数的xor累加到ans里并删除其中一个数,重复操作直到只剩一个数,求ans的最大值
...一开始sb的写了个暴力贪心,在改了1h对拍后才发现naive的贪错了...
于是果断放弃挣扎
如果把比赛的两个人之间连边的话,n-1次操作后就会得到一棵树,实质上一棵树就对应着一种比赛的安排方案
那么这题实际上就是求n*(n-1)边、n个点的最大生成树,边权为两个端点的xor值
type
rec=record
x,y,len:longint;
end;
var
n,tt,tot,tx,ty :longint;
i,j :longint;
ans :int64;
l :array[0..4000010] of rec;
father,a :array[0..2010] of longint;
function get_father(x:longint):longint;
begin
if x=father[x] then exit(x);
father[x]:=get_father(father[x]);
exit(father[x]);
end;
procedure sort(ll,rr:longint);
var
i,j,x:longint;
y:rec;
begin
i:=ll; j:=rr; x:=l[(ll+rr)>>1].len;
while i<=j do
begin
while l[i].len>x do inc(i);
while l[j].len<x do dec(j);
if i<=j then
begin
y:=l[i]; l[i]:=l[j]; l[j]:=y;
inc(i); dec(j);
end;
end;
if i<rr then sort(i,rr);
if j>ll then sort(ll,j);
end;
begin
read(n);
for i:=1 to n do father[i]:=i;
for i:=1 to n do read(a[i]);
tot:=0;
for i:=1 to n do
for j:=i+1 to n do
begin
inc(tot);
l[tot].x:=i; l[tot].y:=j; l[tot].len:=a[i] xor a[j];
end;
sort(1,tot);
tt:=0; ans:=0;
for i:=1 to tot do
begin
tx:=get_father(l[i].x);
ty:=get_father(l[i].y);
if tx<>ty then
begin
inc(tt);
father[tx]:=ty;
inc(ans,int64(l[i].len));
if tt=n-1 then break;
end;
end;
writeln(ans);
end.
——by Eirlys