就是统计每个数不算本身的round数,具体解法如下
前前后后做过三遍,每一次都wa了好多次.........
dp解法:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAX 40
using namespace std;
typedef int LL;
LL dp[MAX][MAX];
void pre ( )
{
dp[1][0] = dp[0][1] = 1;
for ( int i = 0 ; i <= 35 ; i++ )
for ( int j = 0 ; j <= 35 ; j++ )
if ( i == 0 || j == 0 ) dp[i][j] = 1;
else dp[i][j] = dp[i][j-1] + dp[i-1][j];
}
LL calc ( LL n )
{
LL res = 0;
int cnt = 1;
int temp = 0;
if ( n == 0 ) return 1;
while ( n>>temp ) temp++;
temp--;
for ( int i = temp ; i > 0 ; i -- )
{
if ((1<<(i-1))&n)
{
for ( int j = i-1; j+1>=cnt+i-1-j&&j>=0 ; j-- )
res += dp[j][i-1-j];
cnt++;
}
else cnt--;
}
for ( int i = temp-1 ; i >= 0 ; i-- )
{
int temp;
if ( i&1 ) temp = (i+1)/2;
else temp = i/2+1;
for ( int j = i ; j >= temp ; j-- )
res += dp[j][i-j];
}
return res;
}
int main ( )
{
LL n,m;
pre();
while ( ~scanf ( "%d%d" , &n , &m ) )
{
// cout <<"calc : 2 " << calc ( 2 ) << endl;
// cout <<"calc: 12 " << calc ( 12 ) << endl;
printf ( "%d\n" , calc (m+1) - calc ( n ) );
}
}
排列组合解法:
#include <iostream>
#include <cstdio>
using namespace std;
int c[40][40],b[40]; //注意啊,数组还是要取大些好啊,更大的空间总不会出错的,谨记//
//此函数求排列组合C(n,m),即求从m件物品中取n件有多少中取法//
void C()
{
int i,j;
c[0][0]=1;
for(i=1;i<40;i++)
for(j=0;j<=i;j++)
c[i][j]=(j==0)?c[i-1][j]:c[i-1][j]+c[i-1][j-1];
}
//此函数求小于n的数中有多少round number//
int round(int n)
{
int i=n,len=0,j,zero=0;
int ans=0;
while(i)
{
b[len++]=i%2;
i>>=1;
} //求n二进制//
for(i=1;i<len-1;i++) //i+1(i+1<len)位数的二进制位数,第一位必为1,故不计入//
{
for(j=i/2+1;j<=i;j++) //j为其中0的位数//
{
ans+=c[i][j];
}
} //运用排列组合知识,求从i位中取j位为零有多少种并累加//
for(i=len-2;i>=0;i--) //计算位数为len的数中有多少小于n的round number,方法见上//
{
if(b[i])
{
for(j=(len+1)/2-zero-1;j<=i;j++)
{
ans+=c[i][j];
}
}
else zero++; //zero记录在搜索过程中,已发现的0的个数//
}
return ans;
}
int main()
{
int a,b;
scanf("%d%d",&a,&b);
C();
printf("%d\n",round(b+1)-round(a));//此处亦有讲究,由于我们的round()所得为小于n的round number的个数,所以b+1,//
return 0; //此时若b为round number,亦正确//
}
排列组合另一种写法:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
int a ,b ;
int s1[40], s2[40];
int cnt1 = 0 , cnt2 = 0 ;
long long C ( long long index , long long bottom )
{
if ( index > bottom / 2 ) index = bottom - index ;
long long sum1 = 1 , sum2 = 1 ;
for ( long long i = 0 ; i < index ; i ++ )
sum1 *= (long long) ( bottom - i );
for ( long long i = 1 ; i <= index ; i ++ )
sum2 *= ( long long )i;
return sum1/sum2;
}
int c[40][40];
int ans = 0;
void init ( )
{
scanf ("%d%d" , &a , &b );
int zero = 0 , one = 0;
while ( a )
{
s1[++cnt1] = a%2;
a /= 2;
if ( s1[cnt1] ) one++;
else zero++;
}
if ( zero >= one ) ans++;
while ( b )
{
s2[++cnt2] = b%2;
b/= 2;
}
c[0][0] = 1;
for ( int i = 1 ; i <= 35 ; i ++ )
for ( int j = 0 ; j <= i ; j ++ )
{
c[j][i] = C ( j , i );
//cout << c[j][i] << endl;
}
}
int solve ( )
{
int zero = 0;
int one = 1;
int sum1 = 0;
int sum2 = 0;
for ( int i = cnt1-1 ; i > 0 ; i -- )
{
if ( s1[i] == 1 )
{
for ( int j = i-1 ; zero + 1 + j >= one + i -1 - j && j >=0 ; j -- )
sum1 += c[j][i-1];
one++;
//if ( one - zero <= i -1 ) sum1++;
//cout <<i << " "<< sum1 << endl;
}
else zero++;
}
// cout <<sum1 <<endl;
if ( zero >= one ) sum1++;
// if ( one != 2 && s1[1] == 1 && zero + 1 >= one - 1 ) sum1--;
// cout << sum1 <<endl;
for ( int i = cnt1 -2 ; i >= 0 ; i-- )
{
int temp;
if ( i &1 ) temp = ( i +1 )/2;
else temp = i /2 + 1;
for ( int j = i ; j >= temp ; j -- )
sum1 += c[j][i];
}
// cout << sum1 << endl;
zero = 0 , one = 1;
for ( int i = cnt2-1 ; i > 0 ; i -- )
{
if ( s2[i] == 1 )
{
for ( int j = i-1 ; zero + 1 + j >= one + i -1 - j && j >= 0 ; j -- )
sum2 += c[j][i-1];
one++;
// if ( one - zero <= i -1 ) sum2++;
}
else zero++;
}
if (zero >=one ) sum2++;
// if ( one == 1 ) sum2++;
for ( int i = cnt2 - 2 ; i >= 0 ; i -- )
{
int temp;
if ( i&1 ) temp = (i+1)/2;
else temp = i/2+1;
for ( int j = i ; j >= temp ; j -- )
sum2 += c[j][i];
}
//cout << sum2 << endl;
return sum2 - sum1 + ans ;
}
int main ( )
{
init ( );
cout << solve ( ) << endl;
}