【xsy2272】 与运算 状压dp
题目大意:给你一个长度为n的序列a,我们定义fi表示序列a前i项一次进行按位与运算后的值。
我们认为一个序列的价值为∑ni=1fi,现在你要重新排列序列a,使得序列的价值最大。
数据范围,1≤ai,n≤106
我们考虑dp。
不难发现,若序列中存在数x和数y,满足x&y==x,那么将y放在x前面显然是会更优的。
设cnt[i]表示序列a中,有多少个数k,满足i&k==i(此处&表示按位与)
我们f[i]表示以i结尾的序列的最大值是多少,那么显然答案为max0≤i<220f[i]
不难发现有f[i]=maxi&k==if[k]+(cnt[k]−cnt[i])。
如果说直接转移的话复杂度显然是O(nlog32)的,这么搞只能过70的数据。
所以要稍微考虑下转移的性质,我们只需要转移满足k=i+2j的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 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!