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