Codeforces 579D "Or" Game【贪心+暴力按位处理】

D. "Or" Game
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

You are given n numbers a1, a2, ..., an. You can perform at most k operations. For each operation you can multiply one of the numbers by x. We want to make as large as possible, where denotes the bitwise OR.

Find the maximum possible value of after performing at most k operations optimally.

Input

The first line contains three integers n, k and x (1 ≤ n ≤ 200 000, 1 ≤ k ≤ 10, 2 ≤ x ≤ 8).

The second line contains n integers a1, a2, ..., an (0 ≤ ai ≤ 109).

Output

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

Examples
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.


题目大意:

给你N个数,最多可以进行k次操作,每次操作可以选择一个数,使得其变成a【i】*x.

问最终所有数或的值最大是多少。


思路:


1、考虑到或操作的特性:有1的位子上结果就是1.

那么很显然,我们希望得到的结果最大,就要使得最高位尽可能的高。


2、要使得最高位尽可能的高,那么我们希望的就是将K次操作都赋予一个数上,那么这个数一定这个数组中的最大值吗?

显然不是,对于乘法操作中,因为还有*3.*5......这类的操作,就是说在提升最高位的同时,还能使得较小位子上边的1升高。

所以显然不是这个数组中的最大值,那么这个数到底是谁最优呢?

其实我们并不需要太纠结于这个问题。

因为我们可以枚举这个数。

那么我们O(n)枚举出来一个数,将K次操作都赋予这个数上,然后可以通过位压缩的方式,来暴力统计哪些位子上有1.

那么这里可以将O(n^2)的暴力枚举时间复杂度降到O(n*64);


3、细节处理好,注意数据范围。


Ac代码:

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
#define ll __int64
ll a[1005000];
ll po[100];
int have[100];
ll poww(ll a,ll b)
{
    return po[b];
}
void add(ll num,int d)
{
    for(int j=0;j<64;j++)
    {
        ll tm=poww(2,j);
        if((num&tm)!=0)
        {
            have[j]+=d;
        }
    }
}
int main()
{
    ll n,k,x;
    while(~scanf("%I64d%I64d%I64d",&n,&k,&x))
    {
        memset(have,0,sizeof(have));
        for(int i=0;i<n;i++)
        {
            scanf("%I64d",&a[i]);
        }
        ll tmp=1;
        for(int i=0;i<64;i++)
        {
            if(i==0)po[i]=1;
            else po[i]=po[i-1]*2;
        }
        for(int i=0;i<k;i++)
        {
            tmp*=x;
        }
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<64;j++)
            {
                ll tm=poww(2,j);
                if((a[i]&tm)!=0)
                {
                    have[j]++;
                }
            }
        }
        ll output=0;
        for(int i=0;i<n;i++)
        {
            add(a[i],-1);
            a[i]*=tmp;
            add(a[i],1);
            ll sum=0;
            for(int j=0;j<64;j++)
            {
                if(have[j]>0)sum+=(ll)poww(2,j);
            }
            output=max(output,sum);
            add(a[i],-1);
            a[i]/=tmp;
            add(a[i],1);
        }
        printf("%I64d\n",output);
    }
}









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值