• 蓝桥杯 矩阵翻硬币


    矩阵翻硬币

    本文转自 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 }
  • 相关阅读:
    每天进步一点点--&gt;函数fseek() 使用方法
    几种更新(Update语句)查询的方法
    hibernate批量删除和更新数据
    Android ViewPager使用具体解释
    Linux curses库使用
    安装numpy、nltk问题汇总
    android widget 开发实例 : 桌面便签程序的实现具体解释和源代码 (上)
    Eclipse中SVN的安装步骤(两种)和用法
    Intent用法
    Tomcat全攻略
  • 原文地址:https://www.cnblogs.com/1013star/p/10332115.html
Copyright © 2020-2023  润新知