Luogu P4310 绝世好题 题解 [ 绿 ] [ 线性 dp ] [ 单调队列优化 ] [ 二进制优化 ]

题目:绝世好题

暴力 dp

显然 O(n2) 转移即可。

单调队列优化

观察到只有某二进制位两个数都为 1 时才能转移,因此我们把每个二进制位开一个单调队列,然后对于一个数 a ,找到它是 1 的二进制位并选其单调队列的队头进行转移,在这之后把这个数加入符合要求的单调队列中即可。

因为我懒 因为没有弹出元素操作并且多个 log 无伤大雅,所以单调队列可以用优先队列代替。

单调队列的时间是 O(nlogn),要是懒的话用优先队列 O(nlognlogn) 依然可以过。

代码就不写了。

二进制优化

定义 f[i] 为在二进制下以第 i 位为1结尾的最长序列长度。

我们在 dp 时,先找出 a 哪一个二进制位为 1 ,就说明这一位为结尾的可以转移过来,记录下转移最大值。记录之后再找出 a 哪一个二进制位为 1 ,把转移的最大值继续转移下去即可。

#include <bits/stdc++.h>
using namespace std;
int n,a,f[40],ans=0;
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a;
		int tmp=0;
		for(int j=0;j<=32;j++)
		{
			if((a>>j)&1)
			{
				tmp=max(tmp,f[j]);
			}
		}
		for(int j=0;j<=32;j++)
		{
			if((a>>j)&1)
			{
				f[j]=max(f[j],tmp+1);
			}
			ans=max(ans,f[j]);
		}		
	}
	cout<<ans;
	return 0;
}

时间 O(nlogn)

本质是滚动数组充当了我们单调队列的作用,因为它会存下某一位结尾的最大长度,而不用我们手动去找,并且还省空间。

posted @   KS_Fszha  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示