PAT 1049 C++版
1.题意
给出一个正整数N。欲求出1~N这些数字中包括字符1的个数。
例如给出一个数12,从1到12 的数中,包含1的个数一共有5个【1,10,11,12】。
2.分析
这里给出数个简单的方法,如下:
方法一:直接暴力求解,这样在应试的情况下也可以拿到22分。
方法二:寻找某种特殊的关系 这里可见柳神的代码 https://www.liuchuo.net/archives/2305。 我心里只有一个字:膜!
我主要对柳神的代码进行一个简单的介绍。
思想如下: 考察每位取1的次数,然后将这些次数进行一个累积求和,即可得到最终结果。 如下给出一个例子。N=123
。
- step 1:先计算个位上的3,对于个位上可以取到1的次数是13次【
001 , 011 …… 091,101, 111, 121
】。可以看到这个关系是else ans += (left + 1) * a;
- step 2:接着计算十位上的2。可以取到20次,分别是【010—019, 110—119】。对应的关系是:
ans += (left + 1) * a
。 - step 3:接着计算百位上的1。可以取到23次,分别是【100—123】。对应的关系是:
ans += left * a + right + 1
对上面的次数进行一个累加,即可得到最后的一个结果: 13 + 20 + 24 = 57
3.代码
方法一的代码很简单,鄙人不再献丑。
方法二的代码如下:
#include <iostream>
using namespace std;
int main() {
int n, left = 0, right = 0, a = 1, now = 1, ans = 0;
scanf("%d", &n);
while(n / a) {
left = n / (a * 10), now = n / a % 10, right = n % a;
if(now == 0) ans += left * a;
else if(now == 1) ans += left * a + right + 1;
else ans += (left + 1) * a;
a = a * 10;
}
printf("%d", ans);
return 0;
}
5.注意
5.1
2<<30
就是2^31
次方。因为第一个数是2,而不是1.