题目描述
给定一个长度为n的数列ai,求ai的子序列bi的最长长度,满足bi&bi-1!=0(2<=i<=len)。
输入输出格式
输入格式:输入文件共2行。 第一行包括一个整数n。 第二行包括n个整数,第i个整数表示ai。
输出格式:输出文件共一行。 包括一个整数,表示子序列bi的最长长度。
输入输出样例
输入样例#1:
3
1 2 3
输出样例#1:
2
说明
对于100%的数据,1<=n<=100000,ai<=10^9。
Solution:
本题只能说数据很水。
首先很容易套上最长上升子序列的板子,我们设$f[i]$表示以第$i$个数结尾的最长序列长度,则$n^2$枚举转移。
很显然会超时,记得以前做$HNOI$的某道打鼹鼠题目时,介绍过一个玄学优化可行性剪枝(学自巨佬——hzwer),定义个$mx[i]$表示前$i$个数中的最长序列长度,若当前的$f[i]>mx[i-1]$,则直接跳出循环,因为显然最多也只能从前$i-1$个数中的最大长度$mx[i-1]+1$转移过来,而现在$f[i]$至少不比这个值小,所以也就没必要转移了,那么每次求出$f[i]$后,记住要更新$mx[i]=max(mx[i-1],f[i])$(被这卡了好一会儿!`~`),最后答案就是$mx[n]$啦。
代码:
#include<bits/stdc++.h> #define il inline #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--) #define Max(a,b) ((a)>(b)?(a):(b)) using namespace std; const int N=200005; int n,a[N],f[N],mx[N]; il int gi(){ int a=0;char x=getchar();bool f=0; while((x<'0'||x>'9')&&x!='-')x=getchar(); if(x=='-')x=getchar(),f=1; while(x>='0'&&x<='9')a=(a<<3)+(a<<1)+x-48,x=getchar(); return f?-a:a; } int main(){ n=gi(); For(i,1,n) a[i]=gi(),f[i]=1; mx[1]=1; For(i,2,n){ Bor(j,1,i-1) if(mx[i-1]<f[i])break; else if((a[i]&a[j])!=0)f[i]=Max(f[i],f[j]+1); mx[i]=Max(mx[i-1],f[i]); } cout<<mx[n]; return 0; }