首页 > 代码库 > POJ3252 RoundNumbers 【组合数学】

POJ3252 RoundNumbers 【组合数学】

大致题意:

给定left,right,求出[left,right]中有多少数满足如下的性质:化成二进制形式后,0的个数大于等于1

组合数学,各种小边界处理很蛋疼

大致思路是

以10101100为例子,先求[0,10000000)中满足条件的数(想想该怎么求),然后求[100 00000,101 00000),[101 00 000,101 01 000)

[101 01 000,101 01 100)中的,全加起来


一开始思路错了

然后思路对了debug很久发现combination函数写错了。。。

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
long long Combination(long long n,long long r)
{
	if(n==0)
		return 1;
	if(r>n-r)
		r=n-r;
	long long i,j,s=1;
	for(i=0,j=0;i<r;i++)
	{
		s*=(n-i);
		while(s%(r-j)==0&&(r-j)>=2)
		{
			s/=(r-j);
			j++;
		}
	}
	return s;
}
long long cal(long long a)
{
	long long x=1;long long bit=1;
	long long ret=0;
	while(x<=a)
	{
		x<<=1;
		bit++;
	}
	bit--;x>>=1;
//	for(long long i=0;i<=bit/2;i++)
//	{
//		ret+=Combination(bit-1,i);
//	}
	for(long long i=bit-2;i>=0;i--)
	{
		for(long long j=0;j+1<=(i+1)/2 ;j++)
		{
			ret+=Combination(i,j);
		}
	}
	ret+=1;
	long long num1=1,num0=0;
	long long pos=bit;
	while(x>>=1,pos--)
	{
		if(x&a)
			num1++;
		else
			num0++;
		if(x&a)
		{
			for(long long i=pos-1;num0+1+i>=num1-1+pos-1-i && i>=0;i--)
			{
				ret+=Combination(pos-1,i);
			}
		}
	}
	return ret;
}
int main()
{
	#ifndef ONLINE_JUDGE
		freopen("G:/1.txt","r",stdin);
		freopen("G:/2.txt","w",stdout);
	#endif
	long long A,B;
	scanf("%lld%lld",&A,&B);
	printf("%lld\n",cal(B+1)-cal(A));
	return 0;
}