版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/niiick/article/details/82846146
Time Limit: 1 Sec
Memory Limit: 128 MB
Description
给定一个长度为n的数列ai,求ai的子序列bi的最长长度,满足bi&bi-1!=0(2<=i<=len)。
Input
输入文件共2行。
第一行包括一个整数n。
第二行包括n个整数,第i个整数表示ai。
Output
输出文件共一行。
包括一个整数,表示子序列bi的最长长度。
HINT
n<=100000,ai<=2*10^9
题目分析
思路非常巧妙,确实是绝世好题
表示以
结尾的符合要求的序列的最长长度
朴素转移
显然是
的,无法承受
仔细思考是什么时候有
?
显然只要存在任意一位
满足
第
位都是1即可
所以我们考虑新增一个数组
记录满足
第
位是1的
的最大值
那么dp方程变为
其中
第
位是1
这样对于每个dp[i]我们只需要一次
的遍历
总体时间复杂度约为
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
int read()
{
int x=0,f=1;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return f*x;
}
const int maxn=100010;
int n,ans;
int a[maxn],mx[50],dp[maxn];
int main()
{
n=read();
for(int i=1;i<=n;++i) a[i]=read();
for(int i=1;i<=n;++i)
{
for(int j=30;j>=0;--j)
if((1<<j)&a[i]) dp[i]=max(dp[i],mx[j]+1);
for(int j=30;j>=0;--j)
if((1<<j)&a[i]) mx[j]=max(mx[j],dp[i]);
ans=max(ans,dp[i]);
}
printf("%d",ans);
return 0;
}