题目说明
有 100 张写着数字 1~100 的牌,并按顺序排列着。
最开始所有牌都是背面朝上放置。
某人从第 2 张牌开始,隔 1 张牌翻牌。然后第 2, 4, 6, ..., 100 张牌就会变成正面朝上。
接下来,另一个人从第 3 张牌开始,隔 2 张牌翻牌(原本背面朝上的,翻转成正面朝上;原本正面朝上的,翻转成背面朝上)。
再接下来,又有一个人从第 4 张牌开始,隔 3 张牌翻牌...
像这样,从第 n 张牌开始,每隔 n-1 张牌翻牌,直到没有可翻动的牌为止。
求此时所有背面朝上的牌的数字
思路
1.用boolean[]表示这100张牌,false背面朝上;true正面朝上
2.start表示每一轮翻牌的起始下标;skip表示每一轮隔几张牌(为便于理解,所以用两个变量表示,代码层面可以二合一)
3.翻牌:true变false; false变true
代码
public static void main(String[] args) {
boolean[] arr = new boolean[100]; // 表示100张牌,默认是false(背面朝上)
// start表示每一轮翻的第一张牌的下标; skip表示每一轮隔几张牌翻一次
for(int start = 1, skip = 1; start < arr.length; start ++, skip ++){
int i = start;
while(i < arr.length){
arr[i] = !arr[i]; // 翻牌
i += skip + 1; // 注意:相隔s张牌,两张牌的下标相差(s+1)。比如1和4,相隔2张牌,下标相差3
}
System.out.println("skip = " + skip); // 与start的值相同,该变量可以用start代替
print(arr); // 自定义的方法print(xx),便于查看每一轮翻牌后的状态
}
// 统计最终结果,打印为false的牌的数字
for(int i = 0; i < arr.length; i ++){
if(! arr[i]) System.out.print(i+1+" ");
}
}
// 每十个换一行,输出当前数组的内容
private static void print(boolean[] arr){
for(int i = 0; i < arr.length; i ++){
System.out.print((arr[i] ? 1 : 0) + " "); // 1 true; 0 false
if((i+1)%10==0) System.out.println();
}
System.out.println("-------------------");
}
结果
skip = 1
0 1 0 1 0 1 0 1 0 1
0 1 0 1 0 1 0 1 0 1
0 1 0 1 0 1 0 1 0 1
0 1 0 1 0 1 0 1 0 1
0 1 0 1 0 1 0 1 0 1
0 1 0 1 0 1 0 1 0 1
0 1 0 1 0 1 0 1 0 1
0 1 0 1 0 1 0 1 0 1
0 1 0 1 0 1 0 1 0 1
0 1 0 1 0 1 0 1 0 1
-------------------
skip = 2
0 1 1 1 0 0 0 1 1 1
0 0 0 1 1 1 0 0 0 1
1 1 0 0 0 1 1 1 0 0
0 1 1 1 0 0 0 1 1 1
0 0 0 1 1 1 0 0 0 1
1 1 0 0 0 1 1 1 0 0
0 1 1 1 0 0 0 1 1 1
0 0 0 1 1 1 0 0 0 1
1 1 0 0 0 1 1 1 0 0
0 1 1 1 0 0 0 1 1 1
-------------------
......省略......
-------------------
skip = 99
0 1 1 0 1 1 1 1 0 1
1 1 1 1 1 0 1 1 1 1
1 1 1 1 0 1 1 1 1 1
1 1 1 1 1 0 1 1 1 1
1 1 1 1 1 1 1 1 0 1
1 1 1 1 1 1 1 1 1 1
1 1 1 0 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 0
-------------------
1 4 9 16 25 36 49 64 81 100
引申
为啥都是平方数?
1.翻牌次数的奇偶决定了最终正面朝上or背面朝上。(初始背面朝上。翻牌奇数次,正面朝上;翻牌偶数次,背面朝上)
==> 题目转化为:求解翻转了"偶数"次的牌
2.何时翻转?
假设一张牌的数字为n,则当(skip+1)为n的约数时,n会被翻
轮数 | skip+1 | 被翻的牌 | 规律 |
---|---|---|---|
1 | 2 | 2,4,6,8,10,12,... | 2的倍数 |
2 | 3 | 3,6,9,12,15,18,... | 3的倍数 |
3 | 4 | 4,8,12,16,20,24,... | 4的倍数 |
4 | 5 | 5,10,15,20,25,30,... | 5的倍数 |
5 | 6 | 6,12,18,24,30,36,... | 6的倍数 |
6 | 7 | 7,14,21,28,35,42,... | 7的倍数 |
x | x+1 | ———— | (x+1)的倍数 |
比如数字牌12,我们会发现只有当(skip+1)为2,3,4,6,12时,才会被翻牌。而这些数字都是12的约数。
==> 题目转化为:求数字的约数(去掉1后)个数为"偶数"的牌,或者说约数总个数为"奇数"的牌
3.约数总个数为"奇数"的数字都有什么特征?
我们已知:所有约数罗列出来后,首尾两两相乘,得到的就是它本身
数字 | 约数 | 演示 | 备注 |
---|---|---|---|
9 | 1,3,9 | 1*9=9; | 剩3 |
16 | 1,2,4,8,16 | 1*16=16; 2*8=16; | 剩4 |
25 | 1,5,25 | 1*25=25; | 剩5 |
36 | 1,2,3,6,12,18,36 | 1*36=36; 2*18=36; 3*12=36; | 剩6 |
这些数字本身 = 中间那个约数的平方,所以程序最终结果都是平方数也就不足为奇了。