P4310 绝世好题

P4310 绝世好题

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

说明
对于100%的数据,1<=n<=100000,ai<=10^9。


错误日志: 没搞清 每一位的dp值如何更新记录数组


Solution

一个数 \(a\) 可以接在数 \(b\) 后面, 当他们在二进制下有相同位同为 \(1\) 时成立
这启发我们可以这样更新: 对于新的数 \(x\) 的每个 \(1\) 位,向前寻找一个最长的数为前一个转移
可这样复杂度任然无法保证
而想想又发现, 不优值一定不考虑, 我们只用对每一位含 \(1\) 位 保存最大长度即可

我们设置一个数组 \(ton[j]\) 表示到目前为止, 二进制下第 \(j\) 位为 \(1\) 的最长长度
更新第 \(i\) 个数 \(x\) 时, 当 \(x\) 的第 \(j\) 位为 \(1\) 时, 有 \(dp[i] = max(dp[i], ton[j] + 1)\)
更新完答案后需要返回来更新 \(ton[j]\), 当 \(x\) 的第 \(j\) 位为 \(1\) 时, 有 \(ton[j] = max(ton[j], dp[i])\)

Code

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<climits>
#define LL long long
#define REP(i, x, y) for(int i = (x);i <= (y);i++)
using namespace std;
int RD(){
    int out = 0,flag = 1;char c = getchar();
    while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
    while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
    return flag * out;
    }
const int maxn = 200019;
int num;
int dp[maxn], ton[39];
int ans;
int main(){
	num = RD();
	REP(i, 1, num){
		int x = RD();
		REP(j, 1, 31){
			int w = x >> (j - 1);
			if(w & 1)dp[i] = max(dp[i], ton[j] + 1);
			}
		REP(j, 1, 31){
			int w = x >> (j - 1);
			if(w & 1)ton[j] = max(ton[j], dp[i]);
			}
		ans = max(ans, dp[i]);
		}
	printf("%d\n", ans);
	return 0;
	}
posted @ 2018-10-22 19:49  Tony_Double_Sky  阅读(143)  评论(0编辑  收藏  举报