题目描述
小江在找水题时发现了这样一道题:在集合中找出 k ( k≤2)个出现了奇数次的正整数 a。
小江:这不是 sort 的水题吗。
然后他就用暴力水过了这题。
但是这里,为了避免暴力碾标算的情况,本题卡内存(逃
输入格式
第一行两个数 n,k接下来 n 行每行一个正整数表示集合内的元素。
输出格式
从小到大输出一行 k 个数,中间用空格分隔。
样例输入
3 1 2 2 2
样例输出
2
数据范围与提示
40% 的数据满足 k=1且 n 有梯度。
100% 的数据保证 n≤3000000。
保证所有数据正好有 k 个数出现了奇数次。内存限制:4 MiB时间限制:1000 ms
对于k为一的情况:
我们只需要用 “ Λ ” ,就可以愉快的得到四十分了。
对于k为二的情况:
仔细想想,如果依然异或所有的数,我们将得到的是两个答案的异或值。由于两个数不可能相同,所以异或值必然不为零。
讨论异或的每一位可能的组成情况:(假设两个答案分别为a,b)
1 .异或值为零:a,b此位都为一或都为 0 。
2 .异或值为一:a,b中有且只有一个此位为 1 。
借鉴第一种情况的解法,假设在二进制中 x 的位置上的异或值最终为 1 ,我们只需要将所有数中在 x 位置上不为 0 的数全部异或起来,
就能得到最终的 x 位置上的 1 究竟是 a 还是 b 贡献的(找到 a 和 b 中在 x 位置上不为 0 的一个答案)。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,k,x,sum; 4 int t[33]; 5 int main() 6 { 7 scanf("%d%d",&n,&k); 8 for(int i=1;i<=n;++i) 9 { 10 scanf("%d",&x); 11 sum^=x; 12 for(int j=0;j<=30;++j) 13 if(x>>j&1) 14 t[j]^=x; 15 } 16 if(k==1) 17 printf("%d",sum); 18 else 19 { 20 for(int i=30;i>=0;--i) 21 if(sum>>i&1) 22 { 23 printf("%d %d",t[i]^sum,t[i]); 24 break; 25 } 26 } 27 return 0; 28 }
此题加强版-------- k<=500。
对于如此毒瘤的题, hash 就派上用场了。
我们可以将元素全部表示成 a*100000+b的 形式,然后对于每个元素 hash 后存入表中。
再用异或后的a,b 数组尝试组成题目给的元素,再用 hash 进行判断以稍微提高点正确性。
然后就可以愉快的 A 掉此题了。