51Nod1009 数字1的数量

Posted erutsiom

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了51Nod1009 数字1的数量相关的知识,希望对你有一定的参考价值。

题目大意:输入一个十进制数N,计算出从0到N所有数里所有1的个数(注:111里有3个1)

【冷静分析】这道题乍一看有些棘手(实际也不是水题),我们不妨先找找规律。

·一位数里一共有几个1?

答:1。一个。

·两位数里有几个1?

答:个位数是1的:1,11,21,31,……(10个)

十位数是1的:10,11,12,13……(10个)

所以有二十个。

·三位数呢?

答:我不想列举了,有三百个。

等等:1,20,300……

……??????!似乎真的有规律啊!

也就是说,从0——9999(k个9)一共有1的个数是:

f(k)=k(10^k)————①*

惊人的发现啊!我们继续找规律。

不妨以12345这个数为例:

由结论①可知,在1——9999内有4000个1

接下来看10000——12345

我们惊奇地发现,这2346个数的万位都是1,所以答案加上2346

顺着这个思路,我们再来看千位:

当千位为0时,后面的三个数无论是多少,整体都不会超过12345

我们自然想到结论①,这0——999中有300个1

当千位为1时,后面三个数无论是多少,整体也不会超过12345

再加上300,当然,不能忘了千位的1,它一共贡献了1000

当千位为2时,抱歉,路不通了

那我们再看百位。同理:

百位可以固定的数是0,1,2,它们总共会贡献3 * f(2)= 60

百位上的1可以贡献: 100

看十位:固定0,1,2,3,贡献4 * f(1)= 4

十位上的1可以贡献: 10

个位可以是0,1,2,3,4,5,贡献: 1

所以答案是8121

怎么设计程序呢?

首先要注意到的是函数f,可以预处理一下,用数组保存每一个k的f[k]

剩下来的操作虽然冗长,但并不繁杂,涉及到的操作如下:

1、若正在处理的数字是1,计算出1后面的数字m,ans+=m+1(回想加2346的操作)

2、若处理的是个位,若个位不是0,则ans++

3、若正在处理的数字c不是个位也不是1,从0枚举到c-1,ans+=f[s-1](s表示这一位的位数,个位是1,十位是2……)

不要忘了加上这一位上1贡献的数,也就是10 ^ (k-1)

标程如下

?
#include<bits/stdc++.h>
using namespace std;
#define ll long long 
ll f[10];
ll n,ans;
void solve(ll t,int s){
    if(t==1){//处理个位 :1234?中?出现1的可能性 
        for(ll i=0;i<=n%10;i++){
            if(i==1)  ans++;
        }
        return;//证明处理完了 
    }
    ll now=(n/t)%10;//当前正在处理位置上的数字 
    if(now==1)  ans+=n%t+1;//正在处理位置上的数是1:
    //从10000到12345万位上一共可以贡献2346个1
    for(ll i=0;i<now;i++){//这一位上可以固定的数 (如果是1就无效了)
        if(i==1)ans+=t;//这一位可以贡献的1的个数 
        ans+=f[s-1];//s表示这一位是从右往左第几位 
    }
    solve(t/10,s-1);//处理下一位,相应地,s应该右移 
}
int main(){
    ll a,b=1,c=1;
    for(a=1;a<=9;a++){
        f[a]=a;
        for(ll i=1;i<a;i++)f[a]*=10;
    }
    scanf("%lld",&n);
    while(b<n)b*=10,c++;
    solve(b,c);
    printf ("%lld
",ans);
    return 0;
 }

?

以上是关于51Nod1009 数字1的数量的主要内容,如果未能解决你的问题,请参考以下文章

51 Nod 1009 数字1的数量(数位dp)

51nod1009 数字1的数量

51nod 1009 数字1的数量 数位dp

51nod 1009 数字1的数量

51Nod1009 数字1的数量

51nod 1009 - 数字1的数量 - [数位DP][模板的应用以及解释]