现在的位置: 首页 > 综合 > 正文

ACM ICPC 3252 Round Numbers

2013年10月10日 ⁄ 综合 ⁄ 共 6064字 ⁄ 字号 评论关闭

【序言】刚刚开始学,想找些简单的题目入手,看到这题AC的人挺多,于是我也来做做这题。

【题目】

Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 4732   Accepted: 1607

Description

The cows, as you know, have no fingers or thumbs and thus are unable to play Scissors, Paper, Stone' (also known as 'Rock, Paper, Scissors', 'Ro, Sham, Bo', and a host of other names) in order to make arbitrary decisions such as who gets to be milked first.
They can't even flip a coin because it's so hard to toss using hooves.

They have thus resorted to "round number" matching. The first cow picks an integer less than two billion. The second cow does the same. If the numbers are both "round numbers", the first cow wins,
otherwise the second cow wins.

A positive integer N is said to be a "round number" if the binary representation ofN has as many or more zeroes than it has ones. For example, the integer 9, when written in binary form, is 1001. 1001 has two zeroes and two ones; thus,
9 is a round number. The integer 26 is 11010 in binary; since it has two zeroes and three ones, it is not a round number.

Obviously, it takes cows a while to convert numbers to binary, so the winner takes a while to determine. Bessie wants to cheat and thinks she can do that if she knows how many "round numbers" are in a given range.

Help her by writing a program that tells how many round numbers appear in the inclusive range given by the input (1 ≤Start <Finish ≤ 2,000,000,000).

Input

Line 1: Two space-separated integers, respectively
Start
and Finish.

Output

Line 1: A single integer that is the count of round numbers in the inclusive rangeStart..Finish

Sample Input

2 12

Sample Output

6

【思路】

1.首先的想法,就是输入一个数字n,能否令f(n)为那些≤n的"round numbers"的个数?那么题目就可以转化为f(Finish)-f(Start-1).

2.那么如何求这个f(n)?

           1)在求这个f(n)之前,先将n的二进制表达式求出来:(an)(an-1)...(a1)(a0). 当然这个an=1 (第一位是为1的)。后面以n=11,001,001为例做阐述(这是一个8位数)。

           2)个人希望分别找出a)<10,000,000、b)10,000,000~11,000,000、c)11,000,000~11,001,000、d)11,001,000~11,001,001、e)10,101,001之间(左开右闭)的"round numbers"数,那问题不就迎刃而解了吗?!

           3)而a)可以对应成一个7位的“0”“1”串X,XXX,XXX,每一位上任意取0或者1,满足count("0") >= count("1")的字符串的个数.这个为C(7,0)+C(7,1)+...+C(7,3).

这里稍作修改,a)对应成7位+首位是1的字符串;6位+首位是1的字符串;……;

                  b)可以对应成一个6位的“0”“1”串10,000,000+XXX,XXX,每一位上任意取0或者1,满足count("0") +1>= count("1")+1(前2位是10)的字符串的个数.这个为C(6,0)+C(6,1)+...+C(6,3).

                 c)d)类似,e)最后一位的情况特殊处理.

           4)于是需要一个函数用于解决这样的问题:一个k位的“0”“1”串XX...X,每一位上任意取0或者1,满足count("0")+ZeroNum >= count("1")+OneNum的字符串的个数。

于是定义一个函数用于解决这样的问题。

int tempFunction(int k, int ZeroNum, int OneNum)
{
	int temp = ((k+ZeroNum+1-OneNum)%2 == 0) ? ((k+ZeroNum+1-OneNum)/2) : ((k+ZeroNum-OneNum)/2+1);//set the upper bound for count("1")
	//return C(k,0)+C(k,1)+...+C(k,temp-1)
	int sum = 0;
	if (temp <= 0)
	{
		return 0;
	}
	for (int i = 0; i < temp; ++i)
	{
		//杨辉三角的值已计算
		sum = sum + YangHuiTriangle[(k-1)*k/2+i-1];
	}
	return sum;
}

 

其中杨辉三角的值可以用递推公式计算

void InitialYangHuiTriangle(int *TriangleArray, int n)//n是组合数的一个参数,对应杨辉三角的时候,行数多1.
{
	for (int i = 1; i <= n+1; ++i)
	{
		for (int j = 1; j <= i; ++j)
		{
			if ((j == 1) || (j == i) || (i == 1))
			{
				TriangleArray[(i-1)*i/2+j-1] = 1;
			}
			else
			{
				TriangleArray[(i-1)*i/2+j-1] = TriangleArray[(i-2)*(i-1)/2+j-2] + TriangleArray[(i-2)*(i-1)/2+j-1];
			}
		}
	}
}

综合以上的叙述,得到的如下程序:

【程序】

#include<iostream>
using namespace std;

int YangHuiTriangle[(1+25)*25/2];
int SummateArray(int Array[], int n);
void InitialYangHuiTriangle(int *TriangleArray, int n);
int tempFunction(int, int, int);
int RoundNumber(int);
int main()
{
	int StartNum;
	int FinishNum;
	cin >> StartNum  >> FinishNum;
	
	InitialYangHuiTriangle(YangHuiTriangle, 24);
	cout << RoundNumber(FinishNum)-RoundNumber(StartNum-1)<<endl;
	return 0;
}
/*****************************************************************************
*int RoundNumber(int aNumber)
*函数作用:函数用来计算小于等于aNumber的"round number"的个数
*函数输入:十进制整数aNumber (0 <= aNumber <= 20,000,000)
*函数输出:小于等于aNumber的"round number"的个数
*函数备注:暂无
*****************************************************************************/
int RoundNumber(int aNumber)
{
	int countNumber = 0;
	if ((aNumber == 0)||(aNumber == 1))
	{
		return 0;
	}

	int BinaryNumber[24];
	int location = 0;

	while (aNumber != 1)
	{
		BinaryNumber[location] = aNumber%2;
		location = location + 1;
		aNumber = aNumber/2;
	}
	BinaryNumber[location] = 1;
	//这样就将十进制整数转化为二进制表现形式,倒叙放在数组BinaryNumber[24]中

	//接下来是判断1的位置
	int tempFirst1=location-1;
	while(tempFirst1 > 0)
	{
		countNumber += tempFunction(tempFirst1,0,1);
		--tempFirst1;
	}
	int next = location - 1;//已经知道了location(>=1)对应的位置是1了,用next 用以记录下一个1的位置
	int pre = location;
	while (next >= 0)
	{
		if(next == 0)//此时表明这是最后一位
		{
			if(BinaryNumber[next] == 1)//此时pre的位置为1,next的位置也为1
			{
				countNumber += tempFunction(next, pre-next, 1);
				next -= 1;
			}
			else//表明这个数就是aNumber的二进制表达式,只需要验证该数是否为round number 即可
			{
				if (2*SummateArray(BinaryNumber, location+1) <= (location + 1))
				{
					countNumber += 1;
				}
				next -= 1;
			}
		}
		else
		{
			if(BinaryNumber[next] == 1)//此时pre的位置为1,next的位置也为1
			{
				countNumber += tempFunction(next, pre-next, 1);
				pre = next;
				next -= 1;
			}
			else
			{
				next -= 1;
			}
		}
	}
	return countNumber;
}

int tempFunction(int k, int ZeroNum, int OneNum)
{
	if ( k==0 )
	{
		return 0;
	}
	int temp = ((k+ZeroNum+1-OneNum)%2 == 0) ? ((k+ZeroNum+1-OneNum)/2) : ((k+ZeroNum-OneNum)/2+1);//set the upper bound for count("1")
	//return C(k,0)+C(k,1)+...+C(k,temp-1)
	int sum = 0;
	if (temp <= 0)
	{
		return 0;
	}
	for (int i = 0; i < temp; ++i)
	{
		//杨辉三角的值已计算
		sum = sum + YangHuiTriangle[k*(k+1)/2+i];
	}
	return sum;
}

void InitialYangHuiTriangle(int *TriangleArray, int n)//n是组合数的一个参数,对应杨辉三角的时候,行数多1.
{
	for (int i = 1; i <= n+1; ++i)
	{
		for (int j = 1; j <= i; ++j)
		{
			if ((j == 1) || (j == i) || (i == 1))
			{
				TriangleArray[(i-1)*i/2+j-1] = 1;
			}
			else
			{
				TriangleArray[(i-1)*i/2+j-1] = TriangleArray[(i-2)*(i-1)/2+j-2] + TriangleArray[(i-2)*(i-1)/2+j-1];
			}
		}
	}
}



/*****************************************************************************
*int SummateArray(int Array[], int n)
*函数作用:函数用来计算数组的所有元素的和
*函数输入:长度为n的数组Array
*函数输出:数组元素的和
*函数备注:暂无
*****************************************************************************/
int SummateArray(int Array[], int n)
{
	int sum = 0;
	for (int i = 0; i < n; ++i)
	{
		sum = sum + Array[i];
	}
	return sum;
}

【结果】 Runtime Error

 

【修改】 待续

这是从网上搜索来的,发现思路类似,但是本人的比较拙劣

#include<iostream>
using namespace std;
int C[33][33];
int MAX[33];
int B[33];
int tobinary(int b)
{
	int i=1;
	while(b) 
	{  
		B[i++]=b%2; 
		b/=2;
	} 
	return i-1;
}
void init()
{ 
	int i,j;
	C[1][0]=C[1][1]=1;
	for(i=2;i<=32;i++)
	{ 
		C[i][0]=1; 
		for(j=1;j<=i;j++) 
			C[i][j]=C[i-1][j]+C[i-1][j-1]; 
	}
	MAX[1]=0; 
	for(i=2;i<=32;i++) 
	{
		for(j=(i+1)/2;j<i;j++) 
			MAX[i]+=C[i-1][j]; 
	}
}
int howmany(int n,int k,int *p) 
{
	if(k>=n||k<0) 
		return 0; 
	if((n==1&&k==0)||(n==2&&k==1)) 
		return 1; 
	if(p[n-1]==0) 
		return howmany(n-1,k-1,p);
	else
		return C[n-2][k-1]+howmany(n-1,k,p);
}
int compute(int n)
{
	int i,ans=0;
	int len=tobinary(n);
	for(i=(len+1)/2;i<len;i++)
		ans+=howmany(len,i,B);
	for(i=1;i<len;i++)
		ans+=MAX[i];
	return ans;
}
int main()
{ 
	init(); 
	int start,finish;
	cin >> start >> finish; 
	cout<<compute(finish)-compute(start-1)<<endl;
	return 0;
}

抱歉!评论已关闭.