PAT (Advanced Level) Practice - 1049 Counting Ones(30 分)

题目链接:点击打开链接

题目大意:给出一个正整数,应该返回 0 到该正整数之间的十进制形式的 1 出现的个数。

解题思路:累加每一位上“1”的组合数情况总和;以下都是前设在范围不能超过所求的数 n 本身的前提下。

(1)将0,1----n数字列出,为了方便这里假设n为121,也就是000-121

(2)首先看所有数字的个位,这里分为三种情况就是 n 的个位大于1、小于1、等于1。

  • n的个位=1:那么 1 出现的次数为:00“1”-12“1”  前面的数字是变化的从 00-12 有 13 种情况。
  • n的个位>1: 那么 如 122 的情况 1 出现的次数为:00“1”-12“1” 也是 13,但是如果讨论的是十位就不一样了,这是需要重点考虑的。
  • n的个位<1:那么 如 120 的情况,1出现的次数为:00“1”-11“1” 出现的情况是 11 次。

(3)对每个十进制位进行讨论,将结果相加。但是当 n 是十位 、百位(非个位的)的情况下,要相对复杂一点,上面的只是启发一下解题思路。

下面的是正式的解题方法:  

假设数字为:abcde,对于 abcde 中的每一个数字,可以根据该数字与 1 的关系,求在该数字对应位置上1出现的次数。具体来说:假设我们要求百位出现 1 的次数,此时我们可以根据 c 与 1 的关系,求出百位 1 出现的次数。

(1)如果c = 0,则1出现的次数等于:ab * 100,即(c前面的数 * c对应的基数) 在该情况下,百位出现 1 的次数只与 c 前面的数有关。

(2)如果c = 1,则1出现的次数等于:(ab * 100) + (de + 1),即(c前面的数 * c对应的基数) +(c后面的数 + 1)在该情况下,百位出现 1 的次数与 c 前面和 c 后面的数有关。

(3)如果c >= 2,则1出现的次数等于(ab + 1)*100,即(c前面的数 + 1)* c对应的基数。

i.e. 12145
个位5:(1214+1)*10^0==1215
十位4:(121+1)*10^1==1220
百位1:(12)*10^2+(45+1)==1246
千位2:(1+1)*10^3==2000
万位1:2145+1==2146
Result == 7827

AC 代码

#include<bits/stdc++.h>
#include<cmath>

#define mem(a,b) memset(a,b,sizeof a);
#define INF 0x3f3f3f3f
#define MOD 1000000007

using namespace std;

typedef long long ll;

int n, len, rs;
string s;

int fcnt1(int p)
{
    int sum=0,ten=int(pow(10,len-p-1)+0.5),pre=n/(ten*10),post=n%ten;
    char c=s[p];

    if(c=='0') sum+=pre*ten;
    else if(c=='1') sum+=pre*ten + post+1;
    else sum+=(pre+1)*ten;

    return sum;
}

int main()
{
    stringstream ss;
    while(cin>>s)
    {
        ss<<s; ss>>n;
        len=s.length(), rs=0;
        for(int i=0;i<len;i++) rs+=fcnt1(i);
        printf("%d\n",rs);
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/Dream_Weave/article/details/81737825