P4310 绝世好题

题目描述

给定一个长度为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]$啦。

代码:

 1 #include<bits/stdc++.h>
 2 #define il inline
 3 #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
 4 #define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--)
 5 #define Max(a,b) ((a)>(b)?(a):(b))
 6 using namespace std;
 7 const int N=200005;
 8 int n,a[N],f[N],mx[N];
 9 
10 il int gi(){
11     int a=0;char x=getchar();bool f=0;
12     while((x<'0'||x>'9')&&x!='-')x=getchar();
13     if(x=='-')x=getchar(),f=1;
14     while(x>='0'&&x<='9')a=(a<<3)+(a<<1)+x-48,x=getchar();
15     return f?-a:a;
16 }
17 
18 int main(){
19     n=gi();
20     For(i,1,n) a[i]=gi(),f[i]=1;
21     mx[1]=1;
22     For(i,2,n){
23         Bor(j,1,i-1)
24         if(mx[i-1]<f[i])break;
25         else if((a[i]&a[j])!=0)f[i]=Max(f[i],f[j]+1);
26         mx[i]=Max(mx[i-1],f[i]);
27     }
28     cout<<mx[n];
29     return 0;
30 }

猜你喜欢

转载自www.cnblogs.com/five20/p/9108230.html