绝世好题(位运算优化dp)

绝世好题 (位运算优化dp)

题目描述

给定一个长度为 n n n 的数列 a i a_i ai,求 a i a_i ai 的子序列 b i b_i bi 的最长长度 k k k,满足 b i & b i − 1 ≠ 0 b_i \& b_{i-1} \ne 0 bi&bi1=0,其中 2 ≤ i ≤ k 2\leq i\leq k 2ik & \& & 表示位运算取与。

输入格式

输入文件共 2 行。
第一行包括一个整数 n n n
第二行包括 n n n 个整数,第 i i i 个整数表示 a i a_i ai

输出格式

输出文件共一行。
包括一个整数,表示子序列 b i b_i bi 的最长长度。

样例 #1

样例输入 #1

3
1 2 3

样例输出 #1

2

提示

对于100%的数据, 1 ≤ n ≤ 100000 1\leq n\leq 100000 1n100000 a i ≤ 1 0 9 a_i\leq 10^9 ai109


非常难顶的一道题,我几乎把所有题解都看完了,只有几篇能看懂,有些题解表达能力不敢恭维

思维过程:

虽然明知 O ( N 2 ) O(N^2) O(N2) 复杂度会 T T T , 还是要写一发。

ll n,m,_;
int a[N],f[N];
void solve(){
    cin>>n;
    fo(i,1,n)cin>>a[i];
    fo(i,1,n){
        f[i] = 1;
        for(int j=1;j<i;j++){
            if((a[j] & a[i]) !=0){
                f[i] = max(f[i],f[j]+1);
            }
        }
    }
    int ans = 0;
    fo(i,1,n)ans = max(ans,f[i]);
    cout<<ans<<endl;
}

int main(){
	solve();
	return 0;
}

从二进制位的方向考虑,一个贪心的想法就是某位二进制都为 1 1 1 的集合个数的最大值,但是明显有反例

设想这样7个数:
00001
00001
00001
00011 (一个桥梁)
00010
00010
00010
答案不是4而是7

假定正在考虑第 I I I 个数,设 $f[i] $ , ( i 和 I 不 同 ) (i和I不同) (iI) 表示第 i i i 位二进制数都为 1 1 1 的最大序列长度。

考虑转移到 f [ i ] f[i] f[i] (以 a [ i ] a[i] a[i] 结尾的所有满足题目条件选法的集合)的情况,只有和 a [ i ] a[i] a[i] 在某一二进制位上都为 1 1 1 的一组数所组成的序列 b b b 才能转移到 f [ i ] f[i] f[i]

比如:

输入: 
3
1 3 5 (假设最低位标号为1)
----------
1:001 f[1]=1
3:011 f[1]=2,f[2]=1 ; 因为3由于第1位可以跟在1后边,所以f[2]=2
5:101 f[1]=2,f[2]=2 ; f[1]=3,由于f[1]=3导致f[3]=3;
----------
设想这样7个数:
00001
00001
00001
00011 (一个桥梁)
00010
00010
00010
-----------
最后答案明显是7

感觉有点DP套DP,就是和一般的线性dp不同。

int f[30],ans=0;
void solve(){
    cin>>n;
    fo(i,1,n){
        int x;cin>>x;
        int tmp = 0;
        for(int j=0;j<30;j++){
            if(x&(1<<j)){
                tmp = max(f[j]+1,tmp);
            }
        }
        for(int j=0;j<30;j++){
            if(x&(1<<j)){                
                f[j] = tmp;
            }
        }
    }
    for(int i=0;i<30;i++)
   		ans=max(ans,f[i]);
    cout<<ans<<endl;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值