原题传送门
原题描述
- 首先我们来看一下原题是怎么描述的,题面很简单,输入n,然后让我们去统计从1 ~ n之间的自守数有几个,那什么是【自守数】呢,上面也说到了,即一个数在平方之后该数的尾数等于该数自身的自然数
解法一:暴力破解
首先来介绍第一种解法,对 [0, n] 区间内的每个数字求平方,然后对n的几位数字进行是否相等判断,若相等则 count++
思路分析:
- 这里就直接给出代码了,外层循环控制的是从1 ~ n,内部求出当前这个数的平方之后再去一一比对即可,此处的主要判断逻辑就在于这个
tmp % 10 != pow_n % 10
,通过对每一位去做一个比较,若是发现不相同的话那一定不是自守数 - 最后在当前轮的循环结束后,若
tmp == 0
的话则表示所有的位数都比较过了均相同,不是中途break出来的,那么这个数就是【自守数】
代码详解:
int main() {
int n = 0;
int cnt = 0;
cin >> n;
for (int i = 0; i <= n;i++) {
int tmp = i;
int pow_n = pow(i, 2);
while (tmp) {
if(tmp % 10 != pow_n % 10)
break; // 如果遇到不相同的话,直接break
tmp /= 10;
pow_n /= 10;
}
if (tmp == 0) {
cnt++;
}
}
cout << cnt << endl;
}
解法二: 换位取模
思路分析:
- 然后我们再来说说第二种方法此方法我用到了一个
base
作为基数,其到一个临界点的时候就会去发生一个变化那这个【临界点】是什么意思呢?- 当这个数是在10以内的话,那么它就是一个一位数,所以我们在对平方数取余的时候只需要取出最后面那一位就可以了,即
%10
- 当这个数是在100以内的话,那么它就是一个两位数,所以我们在对平方数取余的时候需要取出最后面的两位,即
%100
- 当这个数是在1000以内的话,那么它就是一个三位数,所以我们在对平方数取余的时候需要取出最后面的三位,即
%1000
- 当这个数是在10以内的话,那么它就是一个一位数,所以我们在对平方数取余的时候只需要取出最后面那一位就可以了,即
- 那经过上面这样一分析,你大概也能猜到这个基数
base
该如何变化了吧,也就是当这个i == 10
、i == 100
、i == 1000
…这些临界的时候,就要去更换base
了
代码详解:
int main() {
int n = 0;
while (cin >> n) {
long cnt = 0, base = 10;
for (int i = 0; i <= n; ++i) {
int pow_n = pow(i, 2);
int tmp = i;
// 如果i到达位数的临界点的话, 基数base要发生变化
if (i == base) {
base *= 10;
}
if (pow_n % base == i) {
cnt++;
}
}
cout << cnt << endl;
}
}