给定一个十进制正整数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
思路:一看到这道题就想到了记忆化搜索,奈何太久没打过了,忘记了太多要素,因此被此题卡了四个多小时。。。。。吐血啊
#include<stdio.h> #include<string.h> int dis[12]; int lg,len; int s[12]; int dp[12][2]; int check(int a){ int i=0; if(a<0) return 0; int ans=0; for(i=0;i<=a;i++) ans+=dis[i]*s[i]; //printf("%d %d ",a,ans); return ans; } int dfs(int pos,int lg){ if(pos<0) return 0; int num=lg?dis[pos]:9; // printf("num=%d ",num); if(!lg&&dp[pos][lg]!=-1) return dp[pos][lg]; int i,j; int ans=0; for(i=0;i<=num;i++){//计算当第pos位为i时时,后面pos-1位有多少种情况; (当为i时,计算的范围为i*10^(pos)----(i+1)*10^(pos)-1) if(i==1){ if(lg&&i==num) {ans=ans+check(pos-1)+1+dfs(pos-1,lg&&(i==num));//0---check(pos-1),所以要加一 //printf("a%d %d %d ",pos,i,ans); } else { ans=ans+s[pos]+dfs(pos-1,lg&&(i==num));//当此位为1时,它没有被限制,那么可以分解成10000+(0---9999)(假设当前有五位) //printf("b%d ",ans);//0---9999的每一个数都可以在前面加一个 。 } } else {ans+=dfs(pos-1,lg&&(i==num)); // printf("c%d ",ans); } } // printf("%d %d ",pos,ans); if(!lg) dp[pos][lg]=ans; return ans; } int main(){ int n; len=0; scanf("%d",&n); int i; s[0]=1; for(i=1;i<=9;i++) s[i]=s[i-1]*10; while(n){ dis[len++]=n%10; n=n/10; } memset(dp,-1,sizeof(dp)); printf("%d ",dfs(len-1,1)); return 0; }