题目
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.
输入
Each input file contains one test case which gives the positive N (≤230).
输出
For each test case, print the number of 1's in one line.
样例输入
12
样例输出
5
题意理解
题意太简单了。。。但是题目就不简单了。。。
给你一个数字 问你从1到这个数字之间
一共出现了多少个 1 比如 样例这个是 12
1 2 3 4 5 6 7 8 9 10 11 12
1有一个1 10有一个1 11有两个1 12有一个1 那么1到12总共有5个1
那么统计这个数字从1到这个数字出现了多少位的话
我们可以用经典的数位DP来分析
我们举一个例子
比如这个数是 xxx1yyy
当我们要统计数位的时候 具体统计的某个数位是什么 比如这题统计的是1的个数 以下用 i 表示
我们先将一个数划分为左右两边 从左到右 左边是最高位 右边是最低位
先来看左边 也就是xxx
- 当i不为0时 xxx: 0...0~l - 1 也就是 l *(右边的数的位数)== l*p10
- 当i是0的时候 因为不能有前导0 所以 xxx: 0...1~l - 1 也就是 (l-1) *(右边的数的位数)== (l - 1)*p10
再来看右边 也就是当xxx ==l 时 也就是yyy
- i>dj 0种选法
- i==dj 刚刚好要的那个数就是dj位上的数 那么就有后面位数的所有选法 就是 0...0~r 也就是 r+1 种 也就是 把低位的全部选上 也就是加上r+1种选法
- i<dj 0...0~9...9 也就是加上 10^(右边的数的位数) 种选法 也就是 p10种选法
最后全部加起来就是个数了
代码
#include <bits/stdc++.h>
using namespace std;
int get(int x){
int cnt=0;
while(x){
cnt++;x/=10;
}
return cnt;
}
int power10(int x){
int res=1;
while(x--){
res*=10;
}
return res;
}
int count(int n,int i){
int res=0,dgt=get(n);//dgt 一个数有几位
//从最高位遍历到最后一位 比如一个数是123456 那就从1开始遍历到6
for(int j=1;j<=dgt;j++){
int p10=power10(dgt-j);
//l 是第i位的左边的数 r为右边的数 dj是刚好是j位的数
int l=n/p10/10,r=n%p10,dj=n/p10%10;
/*
因为这里是找1 所有i肯定不是0
那么我们就有0...0~l-1 即 l*10^(右边的数的位数) 就是 l*p10种选法
*/
res+=l*p10;
/*
(1) i>dj 0种选法
(2) i==dj 刚刚好要的那个数就是dj位上的数 那么就有后面位数的所有选法
就是 0...0~r r+1种
也就是 把低位的全部选上 也就是加上 r+1种选法
(3) i<dj 0...0~9...9 也就是加上 10^(右边的数的位数) 种选法 也就是 p10种选法
*/
if(i==dj)res+=r+1;
else if(i<dj)res+=p10;
}
return res;
}
int main(){
int x;
cin>>x;
cout<<count(x,1)<<endl;
return 0;
}