Atcoder Tenka1 Programmer Beginner Contest IntegerotS 【异或+思维】


IntegerotS

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit:262144/262144 K (Java/Others)


Problem Description

Seisu-ya, a store specializing in non-negative integers, sellsN non-negative integers. The i-th integer isAi and has a utility ofBi. There may be multiple equal integers with different utilities.

Takahashi will buy some integers in this store. He can buy a combination of integers whosebitwise OR is less than or equal toK. He wants the sum of utilities of purchased integers to be as large as possible.

Find the maximum possible sum of utilities of purchased integers.

 

Input


Input is given from Standard Input in the following format:


N K
A1 B1
:
AN BN


  • 1N105
  • 0K<230
  • 0Ai<230(1iN)
  • 1Bi109(1iN)
  • All input values are integers.

  

Output


Print the maximum possible sum of utilities of purchased integers. 

 

Sample Input 1


3 5
3 3
4 4
2 5

Sample Output 1


8

Buy 2 and 3 to achieve the maximum possible total utility, 8.


Sample Input 2

Copy
3 6
3 3
4 4
2 5

Sample Output 2

9

Buy 2 and 4 to achieve the maximum possible total utility, 9.


Sample Input 3


7 14
10 5
7 4
11 4
9 8
3 6
6 2
8 9

Sample Output 3


32



【题意】


现在有一系列数,每个数有一个价值,现在问怎么选择数使得所选数的异或和小于等于k,且总价值最大。


【思路】


我们可以去枚举最终的异或值的上限,显然对于满足要求的数来说选得越多越好。那么假设现在枚举的异或值上限为temp,那么只要遍历一遍所有数,只要a[i] | temp==temp,那么加上这个数异或后的值一定不会超过temp。累加满足条件的权值即可。


但是如果一个个暴力枚举的话,显然会超时,那么我们可以想到,先把k用二进制数表示,然后把前几位保留,后几位全部填上一,这一定是最优的策略,能选上更多的数,然后只要枚举中间位置(通过k与2的幂的异或得到)更新最大值即可。


#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define rush() int T;scanf("%d",&T);while(T--)

typedef long long ll;
const int maxn = 100005;
const ll mod = 1e9+7;
const int INF = 0x3f3f3f3f;
const double eps = 1e-9;

int a[maxn],b[maxn];
int jie[maxn];

int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&a[i],&b[i]);
    }
    ll ans=0;
    for(int i=1;i<=n;i++)
    {
        if((a[i]|k)==k)
            ans+=b[i];
    }
    jie[0]=1;
    for(int i=1;i<=29;i++)
    {
        jie[i]=jie[i-1]*2;
    }
    for(int i=1;i<=29;i++)
    {
        if(k&jie[i])
        {
            int temp=(k^jie[i])|(jie[i]-1);  //前面保留,后面全填上1
            ll cnt=0;
            for(int j=1;j<=n;j++)
            {
                if((a[j]|temp)==temp) cnt+=b[j];
            }
            ans=max(ans,cnt);
        }
    }
    printf("%lld\n",ans);
    return 0;
}










  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值