zoukankan      html  css  js  c++  java
  • Codeforces 578B "Or" Game

     传送门

    You are given $n$ numbers $a_1, a_2, dots, a_n$. You can perform at most $k$ operations. For each operation, you can multiply one of the numbers by $x$. We want to make $a_1mid a_2mid dotsmid a_n$ as large as possible, where $mid$ denotes the bitwise OR. Find the maximum possible value of $a_1mid a_2mid dotsmid a_n$ after performing at most $k$ operations optimally.

    Input

    The first line contains three integers $n$, $ k $ and $ x $ ($1 le n le 200000$, $1 le k le 10$, $2 le x le 8$).
    The second line contains $n$ integers $a_1, a_2, dots, a_n$ ($0 le a_i le 10^9$).

    Output

    Output the maximum value of a bitwise OR of sequence elements after performing operations.

    Sample test(s)
    input
    3 1 2
    1 1 1
    output
    3
    input
    4 2 3
    1 2 4 8
    output
    79
    Note

    For the first sample, any possible choice of doing one operation will result the same three numbers 1, 1, 2 so the result is .

    For the second sample if we multiply 8 by 3 two times we'll get 72. In this case the numbers will become 1, 2, 4,72 so the OR value will be 79 and is the largest possible result.


    Solution

    注意到 $2le xle 8$,意味着:每次不论选那个数乘以 $x$,这个数的二进制位数都会增加。

    (其实这不算什么Key Observation,当 $x>1$ 时,$x$ 乘任何正整数,该数的二进制位数都会增加)

    所以要取得最大值,$k$ 次必然都是乘以同一个数,结果的位数就是这个数最后的位数

    所以算法是:

    将输入数组从大到小排序,枚举乘 $x^k$ 后长度最长的数,更新答案。

    为此,预处理出输入数组前缀和后缀取或(|)的结果。

    Implementation

    #include <bits/stdc++.h>
    using namespace std;
    const int N(2e5+5);
    typedef long long ll;
    typedef pair<int,int> P;
    P a[N];
    int f[N], b[N];
    int high_bit(ll x){
        for(int i=62; i>=0; i--){
            if(x&(ll)1<<i) return i;
        }
    }
    int main(){
        int n, k, s;
        scanf("%d%d%d", &n, &k, &s);
        for(int i=1, x; i<=n; i++) scanf("%d", &x), a[i]={x, i};
    
        f[0]=0;
        for(int i=1; i<=n; i++) f[i]=f[i-1]|a[i].first;
        b[n+1]=0;
        for(int i=n; i; i--) b[i]=b[i+1]|a[i].first;
    
        sort(a+1, a+n+1, greater<P>());
        if(!a[1].first){puts("0"); return 0;}
        ll _=1; for(int i=0; i<k; i++) _*=s;
    
        ll ans=0, lar=_*a[1].first;
        int id, h=high_bit(lar);
        for(int i=1; i<=n; i++){
            lar=_*a[i].first;
            if(high_bit(lar)<h) break;
            id=a[i].second;
            ans=max(ans, f[id-1]|b[id+1]|lar);
        }
        printf("%lld
    ", ans);
    }

    比赛时把

    typedef long long ll;

    写成了

    typedef long ll;

    结果交上去连样例都没过,但在自己电脑上却没问题, 这是由于 long / long long 的具体长度依赖于机器 (machine-dependent),

    C++ 标准只规定了其最小长度(minimum size),long(32 bits)long long(64 bits).

    除去这个细节不谈,比赛时还犯了个算法上的错误:

    枚举原来最长的数而不是乘 $x^k$ 后最长的数。

    UPD 2018/3/18

    难道不是用最大的数乘 $x^k$ 吗?

  • 相关阅读:
    旧题复习{6}
    CF219D. Choosing Capital for Treeland [树形DP]
    POJ1947 Rebuilding Roads[树形背包]

    洛谷P1280 尼克的任务[DP]
    NOIP2003pj栈[卡特兰数]
    NOIP2001统计单词个数[序列DP]
    洛谷P1415 拆分数列[序列DP 状态 打印]
    POJ2828 Buy Tickets[树状数组第k小值 倒序]
    CF380C. Sereja and Brackets[线段树 区间合并]
  • 原文地址:https://www.cnblogs.com/Patt/p/4820869.html
Copyright © 2011-2022 走看看