• 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 $ ((2leq ileq 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!令人窒息的错误,样例差评!)

    心如花木,向阳而生。
  • 相关阅读:
    mysql配置图解(mysql 5.5)
    C++中的enum
    vc6.0中的dsp,dsw,ncb,opt,clw,plg,aps等文件的简单说明
    using namespace std
    C#中Cache的使用 迎客
    数据库里的存储过程和事务有什么区别? 迎客
    WINDOWS远程默认端口3389的正确修改方式 迎客
    DES加密和解密PHP,Java,ObjectC统一的方法 迎客
    转:15点 老外聊iPhone游戏开发注意事项 迎客
    windows server 2003 删除默认共享 迎客
  • 原文地址:https://www.cnblogs.com/LLppdd/p/8550983.html
Copyright © 2020-2023  润新知