题解 P4310 【绝世好题】
Limerick
·
·
题解
苹果叶万岁 !!!
此题80分做法就是纯DP,
即f[i]=max{f[j]+1}且j<i且b[i]&b[j]!=0
i从1~n枚举i,j从1~i-1枚举j
这么简单就80分了,不骗分都说不过去啊
那么,100分的代码是什么咧,其实很简单,哦,
其实&的结果最重要的是看两位二进制是否均为1,如果均为1那么&的结果为1,否则为0
那就很好办了,我就搞一个数组f来进行 dynamic programme ,i从1~n枚举每个数,然后枚举这个数的二进制的每一位。
如果某个数二进制的第j位是1,那么f[j]++;f[j]表示到当前状态最后一个数为止的二进制的第j位满足条件的最长子序列长度。
然后将所有等于1的位的f值都换成所有等于1的位上f的最大值即可。
为什么可以换成最大值咧 ?因为一个数的满足条件的二进制位上的f值可以被转移到所有满足条件的二进制位上。
有的同学要问了,怎样求某个数二进制的第i位咧?这时候位运算就闪亮登场了。x&(1<<i)即可求出。
举例1(其实就是样例):1 2 3
转为二进制:01 10 11
0.f[0]=0 f[1]=0
1.f[0]=1 f[1]=0
2.f[0]=1 f[1]=1
3.f[0]=2 f[1]=2
ans=2
举例2:1 3 2 4
转为二进制:001 011 010 100
0:f[0]=0 f[1]=0 f[2]=0
1:f[0]=1 f[1]=0 f[2]=0
2:f[0]=2 f[1]=max(f[1]+1=1,f[0]=2)=2,f[2]=0
3:f[0]=2 f[1]=3 f[2]=0
4:f[0]=2 f[1]=3 f[2]=1
ans=3
其实这题还是需要一点思维的哦。
PS:O(nlogn)搞定
Code:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=35;
int n,ans,f[N],Max;
int main(){
scanf("%d",&n);
for(int j=1;j<=n;j++){//枚举每个数
unsigned int x;//注意了,这里最好用unsigned int
scanf("%ud",&x);//读入时为%ud
Max=0;//最大值赋值为0
for(int i=0;(1<<i)<=x;i++){//枚举这个数的每一位
if(x&(1<<i)){//重点:如果这一位是1!!!
Max=max(Max,f[i]+1);//长度++,并取最大进行f值的转移
}
}
for(int i=0;(1<<i)<=x;i++){
if(x&(1<<i)){//重点:如果这一位是1!!!
f[i]=Max;//转移
}
}
}
for(int i=0;i<32;++i){
ans=max(ans,f[i]);//ans为最长的
}
printf("%d\n", ans);
return 0;
}~~~