zoukankan      html  css  js  c++  java
  • D. Bank Security Unification 题解(二进制dp)

    题目链接

    题目大意

    给你一个长度为(n(2leq nleq 1e6))的数组

    从中选出一个子序列(a)

    那么求出(max sum_{i=2}^{i=len[a[i]]} a[i]&a[i-1])

    题目思路

    参考官方题解

    (dp[i])表前(i)个子序列的最大答案

    首先很容易想到一个(O(n^2))(dp)

    但是显然这样会超时

    这样你肯定会想到用二进制优化(dp),然后就没有然后了。。。

    此题真的有点神奇

    下面我将进行不太严格的证明

    定义(h(x))为不大于x的最大2的幂次

    假设我选了最优子序列

    (f_{j1},f_{j2}...f_{jk})

    (j1leq temp leq j2)

    那么必然在不存在(h(f_{temp}&f_{j1})=h(f_{j2}&f_{j1}))

    原因是为什么

    为了方便设(x=f_{j1},y=temp,z=f_{j2})

    那么假设我(y)存在

    那么序列变成(x,y,z,....)

    若不在序列则变成(x,z....)

    显然答案的变化为

    (x&y+y&z-x&z)

    显然这个值是大于0的,那么放入(y)才是最优选择

    而这个序列却已经是最优序列,代表中间没有(y)

    也就是说我们其实只要考虑二进制中的每一位的最后出现的位置即可

    因为这个二进制的这一位肯定包含和这个元素和他前面的元素的(&)的最高位

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define fi first
    #define se second
    typedef long long ll;
    typedef pair<double,int> pdi;
    const ll INF=0x3f3f3f3f3f3f3f3f;
    const int maxn=1e6+5,mod=1e7;
    int n;
    ll a[maxn];
    ll dp[maxn];
    int last[70];
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i]);
        }
        ll ans=0;
        for(int i=1;i<=n;i++){
            dp[i]=dp[i-1];
            for(int j=0;j<=60;j++){
                if(a[i]&(1ll<<j)){
                    dp[i]=max(dp[i],dp[last[j]]+(a[i]&a[last[j]]));
                    last[j]=i;
                }
            }
        }
        printf("%lld
    ",dp[n]);
        return 0;
    }
    
    
    卷也卷不过,躺又躺不平
  • 相关阅读:
    Linux之vmware安装
    中秋之美
    青春无悔
    MSP430常见问题之指令系统类
    MSP430常见问题之LCD 显示驱动类
    MSP430常见问题之FLASH存储类
    MSP430常见问题之看门狗及定时器类
    MSP430常见问题之电源类
    MSP430常见问题之通信类
    MSP430常见问题之AD转换类
  • 原文地址:https://www.cnblogs.com/hunxuewangzi/p/14508945.html
Copyright © 2011-2022 走看看