zoukankan      html  css  js  c++  java
  • 【xsy2272】 与运算 状压dp

    题目大意:给你一个长度为$n$的序列$a$,我们定义$f_i$表示序列$a$前i项一次进行按位与运算后的值。

    我们认为一个序列的价值为$sum_{i=1}^{n}f_i$,现在你要重新排列序列$a$,使得序列的价值最大。

    数据范围,$1≤a_i,n≤10^6$

     

    我们考虑$dp$。

    不难发现,若序列中存在数$x$和数$y$,满足$x&y==x$,那么将$y$放在$x$前面显然是会更优的。

    设$cnt[i]$表示序列$a$中,有多少个数$k$,满足$i&k==i$(此处&表示按位与)

    我们$f[i]$表示以i结尾的序列的最大值是多少,那么显然答案为$maxlimits_{0≤i<2^{20}}f[i]$

    不难发现有$f[i]=maxlimits_{i&k==i} f[k]+(cnt[k]-cnt[i])$。

    如果说直接转移的话复杂度显然是$O(n^{log_2^3})$的,这么搞只能过$70%$的数据。

    所以要稍微考虑下转移的性质,我们只需要转移满足$k=i+2^j$的$k$即可。

    这样时间复杂度就可以优化到$O(nlog n)$了。

     1 #include<bits/stdc++.h>
     2 #define N 20
     3 #define M (1<<N)
     4 using namespace std;
     5 int cnt[M]={0}; long long f[M]={0},ans=0;
     6 int main(){
     7     for(int n,x=scanf("%d",&n);n;n--) scanf("%d",&x),cnt[x]++;
     8     for(int j=0;j<N;j++)
     9     for(int i=M-(1<<(j+1));i>=0;i--)
    10     if((i&(1<<j))==0)
    11     cnt[i]+=cnt[i+(1<<j)];
    12     for(int i=M-1;~i;i--){
    13         for(int j=0;j<N;j++)
    14         if((i&(1<<j))==0){
    15             f[i]=max(f[i],f[i+(1<<j)]+1LL*i*(cnt[i]-cnt[i+(1<<j)]));
    16             ans=max(ans,f[i]);
    17         }
    18     }
    19     cout<<ans<<endl;
    20 }

     

  • 相关阅读:
    springboot 整合 memcached l
    文件处理工具类 l
    执行脚本工具类 l
    LRU l
    归并排序 l
    Redis 数据类型 l
    git 常用操作命令 唏嘘
    postmanPOST请求 status 415错误 唏嘘
    MySQL 启动和关闭MySQL服务 唏嘘
    OO和OP
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/10582525.html
Copyright © 2011-2022 走看看