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;
}


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