POJ:2719 Faulty Odometer(数学,排列组合)

Faulty Odometer
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 9276   Accepted: 5743

Description

You are given a car odometer which displays the miles traveled as an integer. The odometer has a defect, however: it proceeds from the digit 3 to the digit 5, always skipping over the digit 4. This defect shows up in all positions (the one's, the ten's, the hundred's, etc.). For example, if the odometer displays 15339 and the car travels one mile, odometer reading changes to 15350 (instead of 15340).

Input

Each line of input contains a positive integer in the range 1..999999999 which represents an odometer reading. (Leading zeros will not appear in the input.) The end of input is indicated by a line containing a single 0. You may assume that no odometer reading will contain the digit 4.

Output

Each line of input will produce exactly one line of output, which will contain: the odometer reading from the input, a colon, one blank space, and the actual number of miles traveled by the car.

Sample Input

13
15
2003
2005
239
250
1399
1500
999999
0

Sample Output

13: 12
15: 13
2003: 1461
2005: 1462
239: 197
250: 198
1399: 1052
1500: 1053
999999: 531440

Source

Rocky Mountain 2005


题目大意:有个计程器,它遇到4会跳过去(只要数字里含4就会跳过去),如123,+1的话本应该是124,但它跳过去之后是125;如399跳过去后是500。给你一个跳过去之后的数,让你求这个数实际上是多少?

解题思路:输入n,相当于求1~n中不带4的数的个数。如求13599,我们这样看:

①13599->10000,先求10000以内的不含四的数的个数:那么这些数相当于0xxxx这样,0xxxx这样的数中,根据排列组合,只含一个4的数有c(4,1)*9*9*9种(一个位置选4,其余3个位置的选0~9中不是四的数就行),只含两个4的数的个数为c(4,2)*9*9,只含3个4的数的个数为c(4,3)*9,含4个4的数的个数为c(4,4)这样,10000以内含四的数有1*(c(4,1)*9*9*9+c(4,2)*9*9+c(4,3)*9+c(4,4));

②求10000到13000中含四的数的个数,相当于求0~3000中含四的数的个数,然后就是类似于①了,化为求3000内含四的数的个数:3*(c(3,1)*9*9+c(3,2)*9+c(3,3)),前面乘的三是说3000内第一位可以是0,1,2.

③求13000到13500中含4的数的个数:相当于求0~500中含四的数的个数,结果是5*(c(2,1)*9+c(2,2))+100-(c(2,1)*9+c(2,2)),+100是说最高位为4,那么就有100中情况,-(c(2,1)*9+c(2,2))是说之前5倍的(c(2,1)*9+c(2,2))多算了4开头的数的个数,那么结果就是(5-1)*(c(2,1)*9+c(2,2))+100.

④求13500~13590...

⑤求13590~13599

算出后用n-含四的数的个数就得出结果了。

注意题目中说输入保证不含4.

综合下:对于每一位数x,设这个数所在位数为i(1<=i<=最高位),若x>4则贡献为(x-1)*(∑c(i-1,k)*pow(9,i-1-k)(k∈(1,i-1)))+pow(10,i-1);

若x<4则贡献为(x)*(∑c(i-1,k)*pow(9,i-1-k)(k∈(1,i-1)));

代码如下:

#include <cstdio>
#include <cstring>
#include <cmath> 
#include <algorithm>
using namespace std;
int jiu[10];
int jiecheng[10];
int a[10];
int c[10][10];
void dabiao()
{
	for(int i=0;i<10;i++)//把9的多少次方打表,乘9乘9乘9就不用一个一个算了 
	{
		jiu[i]=pow(9,i);
	}
	jiecheng[0]=1;
	jiecheng[1]=1;
	for(int i=2;i<10;i++)//阶乘打表,为下面的c(n,m)所用 
	{
		jiecheng[i]=jiecheng[i-1]*i;
	}
	for(int i=1;i<10;i++)//题目说最多是999999999,共9位数,那么我们公式中最多用到c(8,8) 
	{
		for(int j=1;j<=i;j++)
		{
			c[i][j]=jiecheng[i]/(jiecheng[i-j]*jiecheng[j]);//排列组合公式 
		}
	}
}
int he(int di)
{
	int q=0;
	for(int i=1;i<=di;i++)
	{
		q=q+c[di][i]*jiu[di-i];
	}
	return q;
}
int calc(int x)
{
	int shu=a[x];
	if(shu<4)
	{
		return shu*he(x-1);//公式 
	}
	else
	{
		return (shu-1)*he(x-1)+pow(10,x-1);//公式 
	}
}
int main()
{
	int n;
	dabiao();
	while(scanf("%d",&n)!=EOF)
	{
		if(n==0)
		{
			break;
		}
		int cnt=1;
		int tmp=n;
		while(tmp)//分解这个数到数组 
		{
			a[cnt++]=tmp%10;
			tmp=tmp/10;
		}
		int ans=0;
		for(int i=cnt-1;i>=1;i--)//对每一位数的贡献进行计算 
		{
			ans=ans+calc(i);
		}
		printf("%d: %d\n",n,n-ans);//算出的是含四的数的个数,记得用n减去它 
	}
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章