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.位运算大力加括号。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |