bzoj4300 绝世好题 【dp】By cellur925
2018-10-30 21:14
330 查看
题目描述:
给定一个长度为\(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("%d\n",ans); return 0; }
AC做法:
其实我们并不需要枚举由谁转移过来。首先这是位运算,我们要有点经验,这个情况一定是按位枚举的,状态量不会很大(\(30\)左右?)我们从位的角度出发:
因为是要求与运算不为0,那么两个数的二进制表示一定存在一位使得两个数的这位都为1.
设\(f[i]\)为数列到目前为止最后一项第\(i\)位为1最长子序列长度,对于每一个新数,我们用它来找到一个它为结尾的最长长度,再用这个最长长度来更新其他答案。
#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]); 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("%d\n",ans); return 0; }
1.和位运算有关的dp从位的角度出发
2.位运算大力加括号。
相关文章推荐
- bzoj 4300: 绝世好题 dp
- bzoj 4300 绝世好题(dp)
- BZOJ4300: 绝世好题(DP)
- BZOJ-4300 绝世好(蛋疼)题 DP(递推)
- BZOJ 4300 绝世好题(DP)
- 【BZOJ4300】绝世好题(二进制,DP)
- BZOJ-4300 绝世好(蛋疼)题 DP(递推)
- 【DP】BZOJ4300 绝世好题
- BZOJ 4300: 绝世好题( dp )
- 【BZOJ4300】绝世好题,位运算相关DP
- 【DP】BZOJ4300[绝世好题]题解
- 【BZOJ】4300 绝世好题 DP
- bzoj4300: 绝世好题(DP)
- bzoj4300: 绝世好题(dp)
- [BZOJ]4300 绝世好题 Dp
- BZOJ 4300(绝世好题-dp)
- [DP] BZOJ4300: 绝世好题
- 【BZOJ4300】绝世好题【DP】【LIS】
- [bzoj4300] 绝世好题 dp
- bzoj 4300: 绝世好题【dp】