51nod 1009 數位dp入門
阿新 • • 發佈:2017-08-20
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示例
12Output示例
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入門