【xsy2272】 与运算 状压dp

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

我们认为一个序列的价值为ni=1fi,现在你要重新排列序列a,使得序列的价值最大。

数据范围,1ai,n106

 

我们考虑dp

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

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

我们f[i]表示以i结尾的序列的最大值是多少,那么显然答案为max0i<220f[i]

不难发现有f[i]=maxi&k==if[k]+(cnt[k]cnt[i])

如果说直接转移的话复杂度显然是O(nlog32)的,这么搞只能过70的数据。

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

这样时间复杂度就可以优化到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 }
复制代码

 

posted @   AlphaInf  阅读(120)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示