1. 程式人生 > >51nod 1009 數位dp入門

51nod 1009 數位dp入門

ext 一位 group code 1出現的次數 alt 收藏 算法 lis

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1009

1009 數字1的數量技術分享

基準時間限制:1 秒 空間限制:131072 KB 分值: 5 難度:1級算法題 技術分享 收藏 技術分享 關註 給定一個十進制正整數N,寫下從1開始,到N的所有正數,計算出其中出現所有1的個數。 例如:n = 12,包含了5個1。1,10,12共包含3個1,11包含2個1,總共5個1。 Input
輸入N(1 <= N <= 10^9)
Output
輸出包含1的個數
Input示例
12
Output示例
5
第一次寫數位dp還是挺頭疼的啊,dp[i][j]表示以j開頭的i位數x=(j+1)*pow(10,i-1)-1,1-x之間所有的數中1出現的次數。
不難寫出方程 dp[i][j]=dp[i][j-1]+dp[i-1][9] 這個自己模擬一下就知道了,
特殊的對於 dp[i][0]=dp[i-1][9] ;
當j==1時上面的方程也要變化為 dp[i][1]=dp[i][j-1]*2+pow(10,i-1),這是因為最高位的‘1‘不能被忽略
之後對於每次詢問的數將他依次拆解計算,
例如對於N=3456,我們先拆出來 [1,2999],也就是 dp[4][2] ,容易發現剩下的數就是 3000-3456,但是3!=1,所以這一段<==> 1-456,這樣每次計算一位就ok,
特殊的對於出現1的位置例如 1234,我們加上dp[4][0]之後剩下的數是 1000-1234,這個1顯然不能拋棄,我們加上234+1個‘1‘之後再把數轉化為 1-234計算就好了。
第一次寫所以寫了個暴力對拍!
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define LL long long
 4 LL mod=1e9+7;
 5 LL dp[15][15];
 6 LL qpow(int,int);
 7 LL bruce(int a,int b)
 8 {
 9     LL s=0;
10     for(int i=a;i<=b;++i)
11     {
12         int n=i;
13         while(n){
14             if(n%10==1) s++;
15             n/=10
; 16 } 17 } 18 return s; 19 } 20 LL qpow(int a,int b) 21 { 22 LL r=1; 23 while(b){ 24 if(b&1) r=r*a; 25 a*=a; 26 b>>=1; 27 } 28 return r; 29 } 30 int main() 31 { 32 int N,i,j,k; 33 for(i=1;i<=9;++i) dp[1][i]=1; 34 for(i=2
;i<=10;++i) 35 { 36 dp[i][0]=dp[i-1][9]; 37 for(j=1;j<=9;++j) 38 { 39 if(j!=1) dp[i][j]=dp[i][j-1]+dp[i-1][9]; 40 else dp[i][j]=2*dp[i][j-1]+qpow(10,i-1); 41 // cout<<i<<‘ ‘<<j<<‘ ‘<<dp[i][j]<<‘ ‘<<bruce(j,i)<<endl; 42 } 43 44 } 45 cin>>N;int nn=N; 46 LL bit=0,s=0,len=log(N+0.5)/log(10)+1; 47 for(i=len;i>=1;--i) 48 { 49 int mul=qpow(10,i-1); 50 int bit_num=N/mul; 51 s+=dp[i][bit_num-1]; 52 N%=mul; 53 if(bit_num==1) s+=N+1; 54 // cout<<"s="<<s<<endl; 55 } 56 cout<<s<<endl; 57 return 0; 58 }

51nod 1009 數位dp入門