您的位置:首页 > 其它

foj 2044 1 M possible 二进制压缩

2016-05-27 00:29 176 查看

题目链接:

http://acm.fzu.edu.cn/problem.php?pid=2044

题意:

给出 一大堆数,找出2个出现次数模3 为1 的两个数字

题解:

把一个数分为几位拆开统计,统计完后,把所有的位数都模三,这样剩下的数就为a和b的叠加了,但是信息丢失太多了,没有办法把a,b区分开。

所以我们要多一个维护,在统计一个数对每一位的贡献的时候,同时统计任意两个位的联系的贡献(mp[i][j]++),这样最后把mp所有记录的联系都mod3剩下的就是a,b各自的联系了,这样就区分开了。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int mp[32][32];
int cnt[32],pos[32],tot;
int main() {
int tc,n,x,a,b,i,j,k,t;
scanf("%d", &tc);
while (tc--) {
memset(cnt, 0, sizeof(cnt));
memset(mp, 0, sizeof(mp));
scanf("%d", &n);
for (i = 0; i < n; i++) {
scanf("%d", &x);
tot = 0;
for (j = 0; j < 31; j++) {
if (x&(1 << j)) {
pos[tot++] = j;
cnt[j]++;
}
}
for (j = 0; j < tot; j++) {
for (k = j + 1; k < tot; k++) {
mp[pos[j]][pos[k]]++;
mp[pos[k]][pos[j]]++;
}
}
}
for (i = 0; i < 31; i++) cnt[i] %= 3;
for (i = 0; i < 31; i++) {
for (j = 0; j < 31; j++) {
mp[i][j] %= 3;
}
}
a = 0;
for (i = 0; i < 31; i++) {
if (cnt[i]) {
cnt[i]--;
a ^= (1 << i);
for (j = 0; j < 31; j++) {
if (mp[i][j]) {
mp[i][j]--; mp[j][i]--;
cnt[j]--;
a ^= (1 << j);
}
}
break;
}
}
b = 0;
for (i = 0; i < 31; i++) {
if (cnt[i]) b ^= (1 << i);
}
if (a > b) { t = a; a = b; b = t; }
printf("%d %d\n", a, b);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: