与运算
题目大意
给出一个长度为
n
的序列
定义一个序列的价值为
数据范围
ai
<=
106
,
n
<=
题解
一个显然的结论,
fi
会随着i的递增而不上升。
设
gi
表示满足
aj
⋁
i
=
设
hi
表示当前找到的与运算前缀和的末位为
i
的答案贡献,不难发现转移式为
也就是枚举上一次找到的不同的前缀和为j,则中间的那一段的前缀和都为i,中间相差的序列长度为
gi
-
gj
,因此中间那段序列的答案贡献为(
gi
-
gj
)*
i
。
至于求
Code(Pascal)
var
a,num,f:array[0..1600000] of int64;
n,m,j,k,l,i,o:longint;
u,ans:int64;
m2:array[0..30] of int64;
function max(a,b:int64):int64;
begin if a>b then exit(a) else exit(b); end;
procedure dg(l,r:longint);//所谓的g数组预处理
var
i,mid:longint;
begin
if l=r then exit;
mid:=(l+r) div 2;
for i:=l to mid do
num[i]:=num[mid-l+i+1]+num[i];
dg(l,mid); dg(mid+1,r);
end;
begin
readln(n);
for i:=1 to n do
begin
read(a[i]);
inc(num[a[i]]);
o:=max(o,a[i]);
end;
o:=trunc(ln(o)/ln(2))+1;
m2[1]:=1; for i:=2 to o+1 do m2[i]:=m2[i-1]*2;
u:=m2[o+1];
dg(0,u-1);
f[u-1]:=(u-1)*num[u-1]; ans:=f[u-1];
for i:=u-1 downto 1 do
begin
ans:=max(ans,f[i]);
for l:=1 to o do
if i and m2[l]>0 then
f[i-m2[l]]:=max(f[i-m2[l]],f[i]+(num[i-m2[l]]-num[i])*(i-m2[l]));
end;
ans:=max(ans,f[0]);
writeln(ans);
end.