蓝桥杯 矩阵翻硬币

矩阵翻硬币

本文转自 https://blog.csdn.net/xiaofengcanyuelong/article/details/79255105
小明先把硬币摆成了一个 n 行 m 列的矩阵。

随后,小明对每一个硬币分别进行一次 Q 操作。

对第x行第y列的硬币进行 Q 操作的定义:将所有第 i*x 行,第 j*y 列的硬币进行翻转。

其中i和j为任意使操作可行的正整数,行号和列号都是从1开始。

当小明对所有硬币都进行了一次 Q 操作后,他发现了一个奇迹——所有硬币均为正面朝上。

小明想知道最开始有多少枚硬币是反面朝上的。于是,他向他的好朋友小M寻求帮助。

聪明的小M告诉小明,只需要对所有硬币再进行一次Q操作,即可恢复到最开始的状态。然而小明很懒,不愿意照做。于是小明希望你给出他更好的方法。帮他计算出答案。

【数据格式】
输入数据包含一行,两个正整数 n m,含义见题目描述。
输出一个正整数,表示最开始有多少枚硬币是反面朝上的。

【样例输入】
2 3

【样例输出】
1

【数据规模】
对于10%的数据,n、m <= 10^3;
对于20%的数据,n、m <= 10^7;
对于40%的数据,n、m <= 10^15;
对于10%的数据,n、m <= 10^1000(10的1000次方)。

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 2000ms


请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

题解:

  

Q 操作的定义:将所有第 i*x 行,第 j*y 列的硬币进行翻转。
(一)、找规律。
1、先看1行m列的矩阵,因为只有1行,当对其进行Q操作的时候,i和x都只能为1,
假设m为5,在对1行5列的矩阵的每个元素进行了Q操作后,推导过程如下:
初始状态:1 1 1 1 1
对(1,1)元素进行Q操作,此时变成0 0 0 0 0
对(1,2)元素进行Q操作,此时变成0 1 0 1 0
对(1,3)元素进行Q操作,此时变成0 1 1 1 0
对(1,4)元素进行Q操作,此时变成0 1 1 0 0
对(1,5)元素进行Q操作,此时变成0 1 1 0 1
综上,可以看出,这五个元素分别翻转了1,2,2,3,2次,很明显,当进行奇数次翻转后为0,当进行偶数次翻转后变为1。那么,我们如果要求最终有几个0,便是求有几个位置可以进行奇数次翻转。
首先,设1<=x<=m,对于(1,m)矩阵中的(1,x)硬币,它翻转了奇数次呢?还是偶数次呢?这时回看到Q操作的定义,会发现这样一个规律:(1,x)位置翻转的次数等于x的约数个数,且当x=k^2(k=1,2,3,4,5,6)时,翻转次数为奇数次,否则为偶数次。
如1行5列矩阵中:
1的约数只有1个,因此(1,1)翻转了1次,
2的约数有2个,因此(1,2)翻转了2次,
3的约数有2个,因此(1,3)翻转了2次,
4的约数有3个,因此(1,4)翻转了3次,
5的约数有2个,因此(1,5)翻转了2次。
当k=1,2时,即x=1,4时翻转奇数次,其他为偶数次。

综上,一个(1,m)矩阵在对每一个元素都进行Q操作后,0的个数为根号下m。

2、那么(n,m)矩阵呢?这里不再赘述,找个简单的矩阵再走一遍流程就会得到下面的结论。
一个(n,m)矩阵在对每一个元素都进行Q操作后,0的个为根号下n乘以根号下m
参考:http://blog.csdn.net/snailset/article/details/26752435

(二)、处理大数开根。
对于100%的数据,n、m <= 10^1000(10的1000次方)。
n,m的最大值是10^1000次方,那么普通的开根已经不适用于这种情况了,在Java中有BigInteger和BigDecimal可以满足这样大数开根的需求。
参考:https://www.cnblogs.com/Annetree/p/6664383.html
最后得出以下代码:

 1 public class Demo {
 2 
 3     public static void main(String[] args) {
 4 
 5         Scanner scanner = new Scanner(System.in);
 6         BigInteger n = scanner.nextBigInteger();
 7         BigInteger m = scanner.nextBigInteger();
 8         BigInteger tem = sqrt(n).multiply(sqrt(m));
 9         System.out.println(tem);
10 
11     }
12     //大数开根--->折半查找法
13     static BigInteger sqrt(BigInteger x) {
14         BigInteger l = BigInteger.ONE;
15         BigInteger r = x;
16         BigInteger temp = BigInteger.ZERO;// 0
17         while (!l.equals(r)) {
18             BigInteger mid = (l.add(r)).divide(BigInteger.valueOf(2));// (l+r)/2
19             // temp!=0&&temp==mid---->mid!=0
20             if (temp.compareTo(BigInteger.ZERO) != 0 && temp.compareTo(mid) == 0) {
21                 break;
22             } else {
23                 temp = mid;
24             }
25             if (temp.compareTo(BigInteger.ZERO) == 0) {
26                 temp = mid;
27             }
28             // mid*mid>x
29             if (mid.multiply(mid).compareTo(x) == 1) {
30                 r = mid;
31             } else {
32                 l = mid;
33             }
34         }
35         if (l.multiply(l).compareTo(x) == 1) {
36             l = l.subtract(BigInteger.ONE);
37         }
38         return l;
39 
40     }
41 }

 

posted @ 2019-01-28 22:40  *starry*  阅读(267)  评论(0编辑  收藏  举报