hdu 4588 Count The Carries

思路:容易发现二进制表示的数的最低位规律是01010101……;接着是001100110011……;接着是:0000111100001111……

这样我们发现每一位的循环节是2^(i+1),前2^i是0,后面的是1.这样就可以算出每一位1出现的次数。

代码如下:

 

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<iostream>
 5 #define ll __int64
 6 using namespace std;
 7 ll a[35]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,
 8 32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,
 9 16777216,33554432,67108864,134217728,268435456,536870912,1073741824,
10 2147483648,4294967296,8589934592,17179869184};
11 ll sa[35],sb[35],s[100];
12 int get(int n)
13 {
14     int bit=0;
15     while(n){
16         bit++;
17         n>>=1;
18     }
19     return bit;
20 }
21 void solve(int n,ll *aa)
22 {
23     ll i,j,nn=n+1;
24     if(n<=0) return;
25     int len=get(n);
26     for(int k=0;k<len;k++){
27         aa[k]+=nn/a[k+1]*a[k];
28         j=nn%a[k+1];
29         if(j>=a[k]) j-=a[k];
30         else j=0;
31         aa[k]+=j;
32     }
33 }
34 int main()
35 {
36     int n,m,len1,len2;
37     ll c;
38     while(scanf("%d%d",&n,&m)!=EOF){
39         memset(sa,0,sizeof(sa));
40         memset(sb,0,sizeof(sb));
41         memset(s,0,sizeof(s));
42         solve(m,sa);
43         solve(n-1,sb);
44         for(int i=0;i<35;i++) s[i]=sa[i]-sb[i];
45         ll ans=0;
46         for(int i=0;i<100;i++){
47             c=(s[i]>>1);
48             ans+=c;
49             s[i+1]+=c;
50         }
51         printf("%I64d\n",ans);
52     }
53     return 0;
54 }
View Code

 

 

 

posted @ 2013-08-20 12:05  _随心所欲_  阅读(309)  评论(0编辑  收藏  举报