题目的意思很清楚。小明提供了一种算法,这里演示一下 n = 2,m = 3 矩阵的翻硬币过程(1 表示 正面, 0 表示反面)
1 |
1 |
1 |
1 |
1 |
1 |
-->(x , y) =(1 , 1)
x的倍数行,y的倍数列要翻转
0 |
0 |
0 |
0 |
0 |
0 |
-->(x , y) =(1 , 2)
x的倍数行,y的倍数列要翻转
0 |
1 |
0 |
0 |
1 |
0 |
-->(x ,y) = (1 , 3)
0 |
1 |
1 |
0 |
1 |
1 |
-->(x , y) = (2 , 1)
0 |
1 |
1 |
1 |
0 |
0 |
-->(x ,y) = (2 , 2)
0 |
1 |
1 |
1 |
1 |
0 |
-->(x ,y) = (2 , 3)
0 |
1 |
1 |
1 |
1 |
1 |
先看 n = 1 的情况:对于(1 , m),只要看它翻转的次数的奇偶就能确定它最终的状态(次数为偶数最后肯定为正面,次数为奇数最后肯定为反面)。因为当x = 1, 确定每次第一行都要参与翻转,当 m 是 y 的倍数的时候,(1 , m)就会翻转,所以(1 , m)全过程翻转的次数取决于 m 的约数个数,1 的约数个数为1 , 3 的约数个数为2, 5 的约数个数为2, 9 的约数个数为3。也就是说当 m = k^2 (k = 1 ,2 ,3···) 其约数个数为奇数,否则 其约数个数为偶数。 因为一般数约数都是成对出现,所以必为偶数,而一个数的平方数,有两个约数相等,所以要减一个相同的就变成了奇数。
所以,对于(1 , m)来说,若m = k^2(k = 1 ,2 ,3···)则最终状态为0,否则为1。
而最后0的个数总和就是我们要的结果
最后得出结论:对于n行m列矩阵,经过 Q 操作后 反面的次数 count = sqrt(n) * sqrt(m) ,(即取整后再相乘)。
找到了公式,又有了对n和m开方的问题,对于n和m输入形式肯定是字符串,所以我们用到了它的长度
假设位数为len的整数,开方取整后为一个lenSqrt位数。
当len为偶数,lenSqrt = len / 2 .
当len为奇数,lenSqrt = (len / 2) + 1 .
现在就简单了,位数确定了之后具体的数既可以从高位到低位一位一位地确定。比如:sqrt(1028),表示对1028开方取整
它开方取整后两位数.先看第一位:
取 0, 00 * 00 < 1028 所以sqrt(1028) >00
取 1, 10 * 10 < 1028 所以sqrt(1028) >10
取 2, 20 * 20 < 1028 所以sqrt(1028) >20
取 3, 30 * 30 < 1028 所以sqrt(1028) >30
取 4, 40 * 40 > 1028 所以sqrt(1028) <40 , 所以第一位取 3 。
第二位:
取 0, 30 * 30 <1028 所以sqrt(1028) > 30
取1, 31 * 31 < 1028 所以sqrt(1028) > 31
取2, 32 * 32 < 1028 所以sqrt(1028) > 32
取3, 33 * 33 > 1028 所以sqrt(1028) < 33 ,所以sqrt(1028) = 32 。
大数是一样的道理,只不过大数用字符串保存,字符串相乘也要自己来实现。
我们用到的函数是对字符串开方,字符串比较,字符串相乘