*PAT_甲级_1049 Counting Ones (30分) (C++)【找规律/详细解释】

目录

1,题目描述

题目大意

2,思路

方法一:纯暴力计算

方法二:找规律

3,代码

方法一

方法二

4,运行结果

方法一

方法二

​ 


1,题目描述

Sample Input:

12

 

Sample Output:

5

题目大意

求0-N之间所有的数所含1的全部个数

 

2,思路

方法一:纯暴力计算

没错就是你想的那样(结果居然还不错,只有两个点超时,30分拿到22,哈哈哈哈哈哈哈哈)

令i从1到N,求出每一个i中含有1的个数,累加即可。

 

方法二:找规律

参考柳神的思路(看了好几遍才看懂。。。)

将数据分成三部分:left(now位左边的各位组成的数),now(当前位),right(now位右边的各位组成的数);

now的取值分三种情况讨论(a为right的位数):

1,now==0,ans += left * a:

eg.1230456,left=123,now=0,right=456.。使now位为1的,共有123*1000.

0001xxx,0011xxx,0021xxx,......1221xxx,1231xxx不存在。从000-122共123。而对于0001xxx-1221xxx中任意一个yyy1xxx来说,xxx取值可从000到999共1000。故ans += 123*1000;

2,now==1,ans += left * a + right + 1:

eg.1231456,left=123,now=1,right=456.。使now位为1的,共有123*1000 + 456 + 1.

这时0001xxx,0011xxx,0021xxx,......1221xxx,1231xxx存在。但1231xxx时,并不能直接乘以1000,所以仍是left * a。将1231xxx单独挑出来计算,xxx从000到456(right),共有456+1.。因此ans += 123 * 1000 + 456 + 1.

3,now >= 2,ans += (left + 1)*  a:

eg.1233456,left=123,now=3,right=456.。使now位为1的,共有(123 + 1)* 1000. 

这时0001xxx,0011xxx,0021xxx,......1221xxx,1231xxx存在,1232xxx,1233xxx。此时1231xxx可以直接乘以1000,所以是(left + 1) * a

 

3,代码

方法一

#include<iostream>
#include<algorithm>
using namespace std;

int getNum(int a){
    int sum = 0;
    while(a > 0){
        if(a % 10 == 1)
            sum++;
        a /= 10;
    }
    return sum;

}
int main(){
//#ifdef ONLINE_JUDGE
//#else
//    freopen("1.txt", "r", stdin);
//#endif

    int input;
    cin>>input;

    int ans = 0;
    for(int i = 1; i <= input; i++){
        ans += getNum(i);
    }
    cout<<ans;
    return 0;
}

方法二

#include<iostream>
#include<algorithm>
using namespace std;

int main(){
//#ifdef ONLINE_JUDGE
//#else
//    freopen("1.txt", "r", stdin);
//#endif

    int N;
    cin>>N;

    int left, right, now, a = 1, ans = 0;
    while(N / a){
        left = N / (a * 10);
        right = N % a;
        now = (N / a) % 10;
        
        if(now == 0) 
            ans += left * a;
        else if(now == 1) 
            ans += (left * a + right + 1);
        else 
            ans += (left + 1) * a;
        
        a *= 10;
    }

    cout<<ans;
    return 0;
}

 

 

4,运行结果

方法一

方法二

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值