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
题目分析
思路非常巧妙,确实是绝世好题
d
p
[
i
]
dp[i]
dp[i]表示以
a
[
i
]
a[i]
a[i]结尾的符合要求的序列的最长长度
朴素转移
d
p
[
i
]
=
m
a
x
(
d
p
[
j
]
)
+
1
(
a
[
i
]
&
a
[
j
]
!
=
0
)
dp[i]=max(dp[j])+1\ (a[i]\&a[j]!=0)
dp[i]=max(dp[j])+1 (a[i]&a[j]!=0)显然是
O
(
n
2
)
O(n^2)
O(n2)的,无法承受
仔细思考是什么时候有
a
[
i
]
&
a
[
j
]
!
=
0
a[i]\&a[j]!=0
a[i]&a[j]!=0?
显然只要存在任意一位
k
k
k满足
a
[
i
]
,
a
[
j
]
a[i],a[j]
a[i],a[j]第
k
k
k位都是1即可
所以我们考虑新增一个数组
m
x
[
k
]
mx[k]
mx[k]记录满足
a
[
j
]
a[j]
a[j]第
k
k
k位是1的
d
p
[
j
]
dp[j]
dp[j]的最大值
那么dp方程变为
d
p
[
i
]
=
m
a
x
(
m
x
[
k
]
)
+
1
dp[i]=max(mx[k])+1
dp[i]=max(mx[k])+1其中
a
[
i
]
a[i]
a[i]第
k
k
k位是1
这样对于每个dp[i]我们只需要一次
l
o
g
a
i
log\ a_i
log ai的遍历
总体时间复杂度约为
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
#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;
}