hdu 3972 1 M possible——位运算

多校确实能学到很多东西呀~~~

看了题解,大概意思是说,这个题是在2*n+1个数中找1个数那种问题的加强版。对于这个简单一点的问题,只要把小球的编号依次异或就可以了,这里就不行,于是我们想到开一个31*31的数组,cnt[i][j],表示第i位是1同时第j位也是1的数字的个数。把整个数组模三,于是整个数组里面就剩下多余的两个数a,b了,我们先来考查cnt[i][i] 。如果a==b,那么cnt[i][i]不是零就是二,那么很容易就得出a,b的值。

如果存在i,使得cnt[i][i]==1,那么不妨设只有a在第i位上是1。那么cnt[i][j]就唯一表示的a了。这样就把a求出来了。然后遍历cnt[i][i],把b求出来就行了。

看了下标程,慢慢学会了位运算。。如果不看标程的话我估计就直接把每个数分解到一个数组里面了,汗……

2011-08-26 11:16:47 Accepted 3972 1109MS 196K 1128 B G++ Tiramitu
#include<cstdio>
#include
<cstdlib>
#include
<cstring>
#include
<cmath>
#include
<algorithm>
#define MAXN 31

using namespace std;

int cnt[MAXN][MAXN],n;

void solve(void)
{
bool single=false;
int singleid;
for(int i=0;i<MAXN;i++)
{
for(int j=0;j<MAXN;j++)
cnt[i][j]
%=3;
if(cnt[i][i]==1)
{
singleid
=i;
single
=true;
}
}
int a=0,b=0;
if(single)
{
for(int i=0;i<MAXN;i++)
{
if(cnt[singleid][i])
a
|=(1<<i);
if(cnt[i][i]==2)
b
|=(1<<i);
else if(cnt[i][i]==1)
{
if(!cnt[singleid][i])
{
b
|=(1<<i);
}
}
}
if(a>b) swap(a,b);
}
else
{
for(int i=0;i<MAXN;i++)
{
if(cnt[i][i])
{
a
|=(1<<i);
b
|=(1<<i);
}
}
}
printf(
"%d %d\n",a,b);
}

int main(void)
{
int T;
scanf(
"%d",&T);
while(T--)
{
memset(cnt,
0,sizeof(cnt));
scanf(
"%d",&n);
for(int v;n--;)
{
scanf(
"%d",&v);
for(int i=0;i<MAXN;i++)
{
if(v&(1<<i))
{
for(int j=0;j<MAXN;j++)
{
if(v&(1<<j))
cnt[i][j]
++;
}
}
}
}
solve();
}
return 0;
}

  

posted @ 2011-08-26 12:34  ω 提拉米兔 ℃  阅读(378)  评论(0)    收藏  举报