BZOJ4300 绝世好题 【dp】

题目

给定一个长度为n的数列ai,求ai的子序列bi的最长长度,满足bi&bi-1!=0(2<=i<=len)。

输入格式

输入文件共2行。
第一行包括一个整数n。
第二行包括n个整数,第i个整数表示ai。

输出格式

输出文件共一行。
包括一个整数,表示子序列bi的最长长度。

输入样例

3

1 2 3

输出样例

2

提示

n<=100000,ai<=2*10^9

题解

按位dp
f[i] = max{f[j] + 1} (存在A[i]二进制某位和A[j]同时为1)
这样做是O(n2)
我们可以将二进制每一位为1时的最优答案储存下来,就可以做到O(32n)的复杂度

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
using namespace std;
const int maxn = 100005,maxm = 100005,INF = 1000000000;
inline int RD(){
    int out = 0,flag = 1; char c = getchar();
    while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
    while (c >= 48 && c <= 57) {out = (out << 1) + (out << 3) + c - '0'; c = getchar();}
    return out * flag;
}
int n,A[maxn][40],f[maxn],mx[40];
int main(){
    n = RD(); int x;
    REP(i,n){
        x = RD(); f[i] = 1;
        for (int j = 1; x; j++,x >>= 1){
            if (A[i][j] = (x & 1)){
                f[i] = max(f[i],mx[j] + 1);
            }
        }
        for (int j = 1; j <= 32; j++)
            if (A[i][j])
                mx[j] = max(mx[j],f[i]);
    }
    int Ans = 0;
    REP(i,32) Ans = max(Ans,mx[i]);
    printf("%d\n",Ans);
    return 0;
}
posted @ 2018-01-07 14:58  Mychael  阅读(123)  评论(0编辑  收藏  举报