51nod 1009 数位dp入门
Posted zzq
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了51nod 1009 数位dp入门相关的知识,希望对你有一定的参考价值。
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1009
基准时间限制: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入门的主要内容,如果未能解决你的问题,请参考以下文章