ZOJ3870 Team Formation

 /**
Author: Oliver
ProblemId: ZOJ3870 Team Formation
*/
/*
思路
1.异或运算,使用^会爆,想到二进制;
2.我们可以试着从前往后模拟一位一位的^那么只要当前位结果变大便是;
3.一般我们如何利用二进制呢?既然要爆那我们就存1的位置;
4.问题是怎么存,如何用?
5.我之前想的是每个数的每位1都存,但是那样造成的重复计算还没想出怎么避免。看了一下别人的博客,再尝试把每位数的最高位1存起来。
6.想想为什么是存最高位呢;
7.那好,现在是不是把所有的高1都存好了,然后我们up(1,n)把原本要和剩余数做异或的步骤变为和bin[]运算。
我们要的是变得比max{A,B}大。那么先看变大,那就要找大一点的那个数,这个时候我们不是和数比较,而是和剩余数的最高位比较。
注意我们要能想到,是以暴力的方法推移过去,做的优化,也就是说每次只要加上可以和这个队伍完成的数目就好了。
注意这样不会有重复(类似A and B,B and A),不会这样。因为有没有发现,每次都是一遍历的这个数为max{A,B}。
注意我们是一位一位往后移,直到吧0->1。
步骤 可以不写吗?思路很详细了吧。
*
#include <cstdio>
#include <cstring>
#include <algorithm> using namespace std; const int MAXM = 100000+10;
int bin[100];
int a[MAXM];
int main()
{
int T,n;
scanf("%d",&T);
while(T--)
{
memset(bin,0,sizeof bin);
scanf("%d",&n);
int X;
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
X=a[i];
for(int j=31;j>=0;j--)//这里若从32开始,你试试会发生什么事
if(X&(1<<j)){//提取最高位
bin[j]++;
break;
}
}
long long ans=0;
int j;
for(int i=0;i<n;i++)
{
X=a[i];
for(j=31;j>=0;j--)
if(X&(1<<j))break;
for(;j>=0;j--)//bin[]运算
if(!(X&(1<<j))){
ans+=bin[j];
}
} printf("%lld\n",ans);
}
}

2015-04-29  22:30:05

上一篇:VS2010提示error TRK0002: Failed to execute command解决方法


下一篇:DB9 公头母头引脚定义及连接、封装