JZOJ 4937 【GDKOI2017模拟1.12】与运算

与运算

题目大意

给出一个长度为 n 的序列a1 a2 ...... an fi 表示序列前 i 项依次进行与运算后的结果。
定义一个序列的价值为ni=1 fi ,现在让你重新排列这个序列,使得这个序列的价值最大,并求出序列最大价值。

数据范围

ai <= 106 , n <=106

题解

一个显然的结论, fi 会随着i的递增而不上升。
gi 表示满足 aj i =aj aj 的个数。
hi 表示当前找到的与运算前缀和的末位为 i 的答案贡献,不难发现转移式为
hi= max ( hi , hj +( gi - gj )* i )其中i j =i
也就是枚举上一次找到的不同的前缀和为j,则中间的那一段的前缀和都为i,中间相差的序列长度为 gi - gj ,因此中间那段序列的答案贡献为( gi - gj )* i
至于求gi可以用分治实现,详见代码。

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.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值