51nod3179 绝世好题

3179 绝世好题

给定一个长度为n的数列a_{i},求a_{i}的子序列b_{i}的最长长度,满足b_{i}&b_{i-1}\neq 0\left ( 2<= i< = len \right )

其中2 <= n <= 100000。

输入

第一行输入一个整数n。
第二行输入n个整数,第i个整数表示ai。

输出

输出一个整数,表示子序列bi的最长长度。

数据范围

30% 2 <= n <= 10
50% 2 <= n <= 100
80% 2 <= n <= 1000
100% 2 <= n <= 100000

输入样例

3
1 2 3

输出样例

2

解析:

f[i] 表示考虑前 i 个数的最长长度,转移为 f[i]=max{f[j]+1}(ai & aj≠0)。

考虑优化,发现这个东西和 LIS 非常类似。由于 a & b≠0 意味着一定有一位为 1,所以我们用 f[i] 表示第 i 位为 1 的最长长度。每次读入一个 x,我们记 s=max{f[i]}+1(x 的第 i 位为 1),然后用 s 去更新 f[i],最后的答案即为 max{ f[i] }。

放代码:

#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;
const int S=31;
char nc(){
    static char s[100000],*p1=s,*p2=s;
    return p1==p2 && (p2=(p1=s)+fread(s,1,100000,stdin),p1==p2)?EOF:*p1++;
}
int read(){
    char c; int x=0; while(!isdigit(c=nc()));
    while(x=x*10+c-'0',isdigit(c=nc())); return x;
}
int f[S];
int main(){
	for(int n=read();n--;){
		int x=read(),t=0;
		for(int j=0;j<S;++j) if(x>>j&1) t=max(f[j],t);
		++t;
		for(int j=0;j<S;++j) if(x>>j&1) f[j]=max(t,f[j]);
	}
	int ans=0;
	for(int i=0;i<S;++i) ans=max(f[i],ans);
	printf("%d",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/ZCH1901/article/details/120070001