码迷,mamicode.com
首页 > 其他好文 > 详细

nyoj-222

时间:2015-03-18 01:02:03      阅读:191      评论:0      收藏:0      [点我收藏+]

标签:

 本题的误区是用位运算法,位运算法基数太大暴力枚举肯定超时。。。

#include <iostream>

using namespace std;

int Count(int n){
 int ans = 0;
 while(n){
  ans += n & 1;  // n 与 1,判断第一位是0还是1 
  n >>= 1;   // 向右移1位 ,相当于 n /= 2
 }
 
 return ans;
}

int main()
{
 int start, end;
 long long ans;
 while(scanf("%d%d", &start, &end) != EOF){
  ans = 0;
  for(int i = start; i <= end; i ++){
   ans += Count(i);
  }
  
  printf("%d\n", ans);
 }

 return 0;
}

肯定会超时,所以本题不适合用位运算法,本题是一个找规律题。

首先观察0-16用二进制表示:

0000

0001

0010

0011

0100

0101

0110

0111

1000

1001

1010

1011

1100

1101

1110

1111

会发现:

第一位的1,每隔2就出现。第二位的1,每隔4出现2次。第三位的1,每隔8出现4次。第四位的1,每隔16出现8次。

所以,可以判断[0-a]中1的个数为:第一位 (a + 1) / 2 ,第二位 (a + 1) / 4  如果(a + 1 ) % 4 > 2 ,则还需要加这部分。

#include <stdio.h>
int gogo(int x)
{
 int y;
 int p = 2, q = 1, sum = 0,temp;
 y = x + 1;        //因为从0000,第二个0001开始计算所以应该加以,把第一个全为零的数也加上
 if (x <= 0)
  return 0;
 while (x >= p / 2)     //当这一次剩下的大约上一次循环的就有没有加到的,所以继续循环
 {
  sum += y / p*q;     //判断这是第几次有几个1
  if (temp = (y%p - p / 2))  //如果余下的大于上一次循环的,就再加上因为这一位中在以前是没有加到过的。
   sum += temp;
  p *= 2;
  q *= 2;
 }
 return sum;
}
int main()
{
 int n, m;
 while (~scanf("%d%d", &n, &m))
 {
  printf("%d\n",gogo(m)-gogo(n-1)); //区间是闭区间,所以包括n要减去n-1;
 }
 return 0;
}

 

nyoj-222

标签:

原文地址:http://www.cnblogs.com/luguo/p/4346043.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!