【异或】小P的集合

题目链接

小P最近对集合非常感兴趣,他看到了这样一个问题:

在集合中找出 (k≤2)个出现了奇数次的正整数 a。

保证所有数据正好有 k个数出现了奇数次。

但是小P的电脑性能非常差,可用内存非常少,只有4MB,所以他想请你帮他写一个程序解决这个问题!


题解:

【小结】:

比赛的时候的确是没有想到,但是我就差一步了。。。就差一步,我已经知道k=1的时候是异或,k=2的时候异或和,至少有一位是1,然后怎么根据这个位置上的1分开为两个呢?我就不懂了。赛后一看题解,就一直骂自己傻逼,就差一步了,我就没想到。

【题解】:

对于这个题目卡内存,就是说根本不能开数组进行存储,一定需要找规律,我们在以前hdu新生题里面就有一题是送礼物的,然后有一个特别的为奇数,然后让我们找出来,所以说,k=1就直接异或和即可。


当k=2时,至少有一位是1。

然后用开数组模拟每一次输入的X,转化为2进制后,最大只有31位。

开一个cnt[32]的数组。

只要有转化后只要对应位置有1的,把cnt[i]^=x。

为什么进行这个操作,大家想想,k=2时,其余位置肯定都是偶数对,我们转化为二进制的  i位置上,即

\large x=\sum_{i=0}^{31}2^i

然后对于每一个为1的位置都进行异或,相当于对于i位置有x的出现过。

输入n个x后,

最后就会转化为\large a \wedge b=c,怎么通过求a,b呢??

从高位枚举,我们知道至少有一位是1,那么我们a=c^cnt[i],那么b=cnt[i]

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=40;
ll cnt[N];
ll n,k,x,sum;
int main()
{
    scanf("%lld%lld",&n,&k);
    for(int i=1;i<=n;i++){
        scanf("%lld",&x);
        for(int j=31;j>=0;j--){
            if((1<<j)&x){
                cnt[j]^=x;
            }
        }
        sum^=x;
    }
    ll a,b;
    if(k==1){
        return 0*printf("%lld\n",sum);
    }
    for(int i=31;i>=0;i--){
        if((1<<i)&sum){
            a=sum^cnt[i];
            b=cnt[i];
            return 0*printf("%lld %lld\n",a,b);
        }
    }

}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值