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

 

 

 

你可能感兴趣的:(count)