1. 程式人生 > >統計數字問題(10^9的大數)

統計數字問題(10^9的大數)

問題描述:一本書的頁碼從自然數1 開始順序編碼直到自然數n。書的頁碼按照通常的習慣編排, 每個頁碼都不含多餘的前導數字0。例如,第6 頁用數字6 表示,而不是06 或006 等。數 字計數問題要求對給定書的總頁碼n,計算出書的全部頁碼中分別用到多少次數字0,1, 2,…,9。

資料輸入:每個檔案只有一行,給出表示書的總頁碼的整數n(1<=)

資料輸出:輸出檔案共10行,在第k(k=1,2,3...10)行輸出頁碼中用到數字k-1的次數

輸入檔案示例:11

輸出檔案示例:1 4 1 1 1 1 1 1 1 1

 問題分析:

拿到題第一感覺是直接從1迴圈到n,然後計算每一位的數字計算總數

for(int i=1;i<=n;i++){
	while(i/10){
		total[i%10]++;
		i/=10;
	}
}

可以看到,隨著n的增大,程式的時間複雜度也在增大,所以方法不可取

然後我就用老師上課講的方法試說一下吧

演算法核心思想是考慮數字k在每個位上出現的次數然後加和

然後現在來找規律

拿9527舉例吧,現在十位上是2,假設考慮十位上的數比2大,例如3,則十位上出現3的數字為

30-39  130-139....9430-9439 共(94+1)*10個

假設考慮十位上的數比2小,例如1,則十位上出現數字2的數字為

10-19  110-119....9510-9519 共(95+1)*10個

假設考慮十位上的數等於2,則十位上出現2的數字為

20-29 120-129....9420-9429 9520-9527 共(94+1)*10+(個位+1)

 

再用百位上的5舉例,現在百位上是5,假設考慮百位上的數比5大,例如6,則百位上出現6的數字為

600-699  1600-1699....8600-8699 共(8+1)*100個

假設考慮百位上的數比5小,例如3,則百位上出現數字3的數字為

300-399  1300-1399....9300-9399 共(9+1)*100個

假設考慮百位上的數等於5,則百位上出現5的數字為

500-599 1500-1599....8500-8599 9500-9527 共(8+1)*100+(後兩位+1)

 

然後假設當前位為cur,該位之前的數字為high,該位之後的數字為low,cur所在的位的權重為weight(十位為10,百位為100),則可以總結出的規律為:

        k < cur時,k在該位出現的次數為(high+1)*weight

        k > cur時,k在該位出現的次數為 high*weight

        k = cur時,k在該位出現的次數為 high*weight+low+1

Note:

因為0前必須有數字,所以需要單獨考慮0

看程式碼吧還是

#include<iostream>
#include<cstring>
using namespace std;

__int64 total[10];//記錄每個數出現的個數 

int main(){
	int n;
	__int64 low,cur,high;
	int weight=1;//權值 
	cout<<"Enter the total page number n:";
	cin>>n;
	memset(total,0,sizeof(total));
	
	while(n/weight){//將0單獨考慮 
		low=n%weight;//當前位之後的數字 
		cur=(n/weight)%10;//當前位 
		high=n/(weight*10);//當前位之前的數字
		if(!high){
			weight*=10;
			continue;
		}
		else if(cur==0){
			total[0]+=((high-1)*weight+low+1);
		}
		else{
			total[0]+=high*weight;
		}
		weight*=10; 
	}
	
	weight=1;
	while(n/weight){//1~9直接按照規律
		low=n%weight;//當前位之後的數字 
		cur=(n/weight)%10;//當前位 
		high=n/(weight*10);//當前位之前的數字 
		for(int i=1;i<=9;i++){ 
			if(i<cur){
				total[i]+=(high+1)*weight;
			}
			else if(i>cur){
				total[i]+=(high*weight);
			}
			else if(i==cur){
				total[i]+=(high*weight+low+1);
			}
		}
		weight*=10;
	}
	
	for(int i=0;i<=9;i++){
		cout<<total[i]<<endl;
	}
	return 0;
}