SOJ 3598 Binary

题目连接:http://zuojie.3322.org:88/soj/problem.action?id=3598

 

Description

For the sequence 0, 1, 2, . . , n, you are required to caculate the number of 
'1's when we write them in binary form.

Input

Multiple test cases, please process till EOF.
For each test case, there is only one line containing only one integer n
(0<=n<2^31).

Output

For each test case, output the answer in a single line.

Sample Input

5
1164
20071010
20100512
835672545

Sample Output

Case 1: 7
Case 2: 5744
Case 3: 239720074
Case 4: 240071643
Case 5: 12245574353

解题思路:

 

首先观察题目的数据量:是2^31,所以直接暴力+位运算肯定是不可行的。

那么我们可以观察一下二进制数的规律:

00000

00001

00010

00011

00100

00101

00110

00111

01000

01001

01010

01011

01100

01101

01110

01111

10000

以上是0-16的十进制数的二进制码,我们可以很容易发现,最后一位为1的个数是n的一半

第二位如果足够长的话也应该是一半

具体地说:最后一位一次出现0一次出现1,第二位两次出现0两次出现1,第三位四次出现0再四次出现1。

于是可以归纳一下,第n位就有:先出现2^(n-1)次0,再出现2^(n-1)次1。循环节是2^n

于是剩下的工作就非常的简单了

PS:注意到,n比较大,所以计算出来的结果会超过int,所以要用long long,另外SOJ不支持__int64这种数据类型。。

 

我的代码:
#include<stdio.h> #include<iostream> using namespace std; long long POW(long long a,long long n) { long long i,ret=1; for(i=1;i<=n;i++) ret=ret*a; return ret; } int main() { long long n,i,t=1,ans,s,a,b; while(cin>>n) { ans=0; ans=ans+(n+1)/2; for(i=2;i<=31;i++) { s=n-(POW(2,i-1)-1); if(s<0) break; a=POW(2,i); b=a/2; ans=ans+(s/a*b); if(s%a>b) ans=ans+b; else ans=ans+s%a; } cout<<"Case "<<t<<": "<<ans<<endl; t++; } return 0; }

你可能感兴趣的:(SOJ 3598 Binary)