bzoj 4300 绝世好题

Posted LLppdd

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 4300 绝世好题相关的知识,希望对你有一定的参考价值。

绝世好题

Time Limit: 1 Sec Memory Limit: 128 MB

Submit: 2520 Solved: 1365

Description

给定一个长度为\(n\)的数列\(a_i\),求\(a_i\)的子序列\(b_i\)的最长长度,满足\(b_i \ \& \ b_{i-1}!=0\ \) \((2\leq i\leq len)\)

Input

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

Output

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

Sample Input

3
1 2 3

Sample Output

2

HINT

\(n<=100000,ai<=2*10^9\)

一眼dp(233???)。。。
然而数据范围piapia打脸。。。(笑嘻嘻?)
想想,咋办啊?dp是肯定的了(不然我真的没什么想法了。。。)
仔细想想,这名字很强啊,一定有什么妙妙的地方。。。
题目中只有一个条件,那么想一想什么时候两个数&起来是0呢?
发现只要两个数在二进制下有一位都是1,那么&起来就不是0.。。。
所以我们换一种方式来dp一下
数组\(dp[i]\)对应选出数列的最后一个数在二进制下的第\(i\)位为1的最优解,也就是说,最后一个数的二进制下第\(i\)位是1的数列长度最优下是\(dp[i]\)个。
这样一设出来后,转移就让人很开心了啊。
枚举每一个数,如果满足条件就更新它,详细的可以看代码(记得最后顺手维护一下\(dp\)数组o)

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int n, ans;
int a[maxn], dp[30];
int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    for(int i = 1; i <= n; ++i)
    {
        int tmp = 0;
        for(int k = 0; k <= 30; ++k)  if((a[i] & (1 << k))) tmp = max(tmp, dp[k] + 1);
        for(int k = 0; k <= 30; ++k)  if((a[i] & (1 << k))) dp[k] = tmp;
        ans = max(ans, tmp);
    }
    cout << ans;
    return 0;
}

(if里面判断的时候,注意位运算的运算顺序aaa!令人窒息的错误,样例差评!)

以上是关于bzoj 4300 绝世好题的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ-4300: 绝世好题 (递推)

bzoj 4300: 绝世好题

bzoj 4300 绝世好题

bzoj4300 绝世好题

BZOJ 4300 绝世好题(位运算)

[bzoj 4300]绝世好题