zju pat

1049. Counting Ones (30)

 

The task is simple: given any positive integer N, you are supposed to count the total number of 1's in the decimal form of the integers from 1 to N. For example, given N being 12, there are five 1's in 1, 10, 11, and 12.

Input Specification:

Each input file contains one test case which gives the positive N (<=230).

Output Specification:

For each test case, print the number of 1's in one line.

Sample Input:
12
Sample Output:
5

 

 

顺便替浙大 pat 考试 搞个小宣传,大家可以去http://pat.zju.edu.cn/看看,有考试时候的一些习题,参加pat考试也会发个证书的,对锻炼自己编程能力算是不错的。这题主要是求1的个数,因为数据量比较大2的30次次方,暴力后面的肯定是超时。我们可以这么想,比如242这个数,我们可以这么想,可以分为200以下和200以上这两个段,我们只看200以下百位上的数字,从100-199这100个数,百位总共是100个1,然后百位下面的怎么想,我们可以想到从000-199这200个数字中,十位和个位中,每个数字出现的次数是相等的,所以我们可以用200*(1/10),就可以得到000-199这200个数所有的十位和个位上的1。接下来我们考虑200以上,也就是200-242这段数字,因为百位所有情况我们都已经考虑过,所以我们只需要考虑00-42这段数字,也就是可以划成对42求含有1的个数,这样可以一直前进。当然我们要注意一下142的不同之处,也就是开头是1的时候,这个时候没有从100-199的100个1,百位是从100-142 所以需要加上43个1。

还是太水咯,继续努力啊。。。

 

 

#include<iostream>
using namespace std;

long long dp[13];
long long find(long long n)
{
    long long k, len, sum, num, num1, num2, p, i;
   
    k = n;
    len = 0;
    while(k != 0)
    {
        len++;
        k = k/10;        
    }

    sum  = 0;
  
    for(i = len; i >= 1; --i)
    {
         num1 = n/dp[i-1];
         num2 = n-dp[i-1]*num1;

         if(num1 == 0)
         {
             continue;        
         }
         else if(num1 == 1) 
         {
             sum = sum+num2+1; 
             p = ((i-1)*dp[i-1])/10;
             sum = sum+p;
             n = n - num1*dp[i-1]; 
         }
         else 
         {
             sum = sum+dp[i-1];
             p = (i-1)*(num1*dp[i-1])/10;
             sum = sum + p;   
             n = n - num1*dp[i-1];
         }
    } 
    return sum;
     
} 
int main()
{
    long long n, i, j;
        
    dp[0] = 1;
    for(i = 1; i <= 10; ++i)
    {
       dp[i] = dp[i-1]*10 ;      
    }
    j = 1;
    for(i = 1; i <= 30; ++i)
    {
        j = j*2;       
    }
    while(cin>>n)
    {
         cout<<find(n)<<endl;            
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值