pat甲级1049 Counting Ones (30 分)

欢迎访问我的pat甲级题解目录哦 https://blog.csdn.net/richenyunqi/article/details/84981078

题目描述

pat甲级1049 Counting Ones (30 分)_第1张图片

算法设计

显然暴力枚举的方法是不可取的,我们需要寻找其中的规律,本题中可以分别计算出每一位的1出现的个数再进行加和。本博客中以数字N=345N=305N=315为例,寻找十位数字上是1的数字个数。将数字分成3部分:百位、十位、各位。
显然,从1~345这345个数中,百位数字可以出现0、1、2、3四种,每种百位数字都可以跟一个数字为1的十位,而每种十位数字可以跟0~9这十种数字,所以从1~345这345个数中,十位数字为1的数共有 ( 3 + 1 ) × 10 = 40 (3+1)×10=40 (3+1)×10=40个,故十位上的1共出现40次。
N=305时,百位数字依然可以出现0、1、2、3四种,但要注意,百位数字为3时,后面不能再跟数字为1的十位,因为这样的数字已经大于305了,所以从1~305这305个数中,十位数字为1的数共有 3 × 10 = 30 3×10=30 3×10=30个,故十位上的1共出现30次。
N=315时,百位数字依然可以出现0、1、2、3四种,此时要注意,百位数字为3时,后面可以再跟数字为1的十位,但这样的数字个位上只能出现0~5这6个数,即310、311、312、313、314、315,其他数字都会大于315,所以从1~315这315个数中,十位数字为1的数共有 3 × 10 + ( 5 + 1 ) = 36 3×10+(5+1)=36 3×10+(5+1)=36个,故十位上的1共出现36次。

综上,对于任意一个数字N,当要判断从右向左数第i位上1出现的次数num时,可以将这个数字分成三部分,分别用leftcurrentright表示,即left=数字N在i位左侧的数字current=数字N在第i位的数字right=数字N在i位右侧的数字。例如数字N=123456,判断从右向左第2位也就是百位上,即数字4所在位置1出现的次数时,left=123current=4right=56。此时分三种情况进行计算:

  1. c u r r e n t = 0 current=0 current=0 n u m = l e f t × 1 0 i num=left×10^i num=left×10i
  2. c u r r e n t = 1 current=1 current=1 n u m = l e f t × 1 0 i + ( r i g h t + 1 ) num=left×10^i+(right+1) num=left×10i+(right+1)
  3. c u r r e n t > 1 current>1 current>1 n u m = l e f t × 1 0 i + 1 0 i num=left×10^i+10^i num=left×10i+10i

C++代码

#include
using namespace std;
int main(){
    int N,ans=0;
    scanf("%d",&N);
    int left=N/10,right=0,current=N%10;
    for (int i=1;right!=N;i*=10) {
        ans+=left*i+(current==0?0:current==1?(right+1):i);
        right+=current*i;
        current=left%10;
        left/=10;
    }
    printf("%d",ans);
    return 0;
}

你可能感兴趣的:(pat甲级)