加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

bzoj4300 绝世好题 【dp】By cellur925

发布时间:2020-12-14 04:16:38 所属栏目:大数据 来源:网络整理
导读:题目描述: 给定一个长度为 (n) 的数列 (a) ,求 (a) 的子序列 (b) 的最长长度,满足bibi-1!=0( (2=i=len) )。 90分做法: 并没有部分分,但是我们可以很容易地想出 (O(n^2)) 算法:诸如最长上升子序列。 但是一定要注意 位运算需要大力加括号,

题目描述:

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

90分做法:

并没有部分分,但是我们可以很容易地想出(O(n^2))算法:诸如最长上升子序列。

但是一定要注意位运算需要大力加括号,就算是与运算!!(因为这个WA了好几次hhh)

#include<cstdio>
#include<algorithm>

using namespace std;

int n,ans;
int a[100090],f[100090];

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)
    {
        f[i]=1;
        for(int j=1;j<i;j++)
            if((a[i]&a[j])!=0) f[i]=max(f[i],f[j]+1);
        ans=max(ans,f[i]);
    }
    printf("%dn",ans);
    return 0;
}

AC做法:

其实我们并不需要枚举由谁转移过来。首先这是位运算,我们要有点经验,这个情况一定是按位枚举的,状态量不会很大((30)左右?)我们从位的角度出发:

因为是要求与运算不为0,那么两个数的二进制表示一定存在一位使得两个数的这位都为1.

(f[i])为数列到目前为止最后一项第(i)位为1最长子序列长度,对于每一个新数,我们用它来找到一个它为结尾的最长长度,再用这个最长长度来更新其他答案。

#include<cstdio>
#include<algorithm>

using namespace std;

int n,&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        int qwq=0;
        for(int j=0;j<=30;j++) 
            if(a[i]&(1<<j)) qwq=max(qwq,f[j]+1);
        for(int j=0;j<=30;j++)
            if(a[i]&(1<<j)) f[j]=max(f[j],qwq); 
    }
    for(int i=0;i<=30;i++)
        ans=max(ans,f[i]);
    printf("%dn",ans);
    return 0;
}

1.和位运算有关的dp从位的角度出发

2.位运算大力加括号。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读