Codeforces 578B "Or" Game

本文介绍了一个算法问题,即通过执行最多k次操作,每次将序列中的一个数乘以x,来最大化序列元素的位或运算结果。文章给出了具体的实现思路与代码示例,并对关键步骤进行了说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 传送门

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_1\mid a_2\mid \dots\mid a_n$ as large as possible, where $\mid$ denotes the bitwise OR. Find the maximum possible value of $a_1\mid a_2\mid \dots\mid 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

注意到 $2\le x\le 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\n", 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$ 吗?

 

转载于:https://www.cnblogs.com/Patt/p/4820869.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值