蓝桥杯 历届试题 PREV-34 矩阵翻硬币

历届试题 矩阵翻硬币

时间限制:1.0s   内存限制:256.0MB

问题描述

  小明先把硬币摆成了一个 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次方)。

题目解析:  

  1、从题目得知,如果一个硬币被翻转了奇数次后为正面朝上,那么它原始的状态一定是反面朝上。因此,我们需要统计所有翻转了奇数次硬币的个数。

  2、题目中的 “ 对第x行第y列的硬币进行 Q 操作的定义:将所有第 i*x 行,第 j*y 列的硬币进行翻转 ”。我们可以试着逆向思索,对于一个横坐标为X的硬币而言,我们翻转那些硬币会影响到它而使它翻转呢?由此我们可以得出,当翻转的硬币的横坐标为X的约数时,会影响到它的翻转。比如,X=9,那么翻转横坐标为 1、3、9的时候会影响到它的翻转。纵坐标情况同理。

    对于一个硬币,我们必须考虑到它的横坐标和纵坐标。假如,此硬币的横坐标翻转了5次,纵坐标翻转了6次,那么它总的翻转次数为 5 * 6 = 30 次。因此我们得到一个公式:总翻转次数 (count) = 横坐标翻转次数 (count_x) * 纵坐标翻转次数 (count_y)。我们一开始就指出,我们需要找到翻转了奇数次的硬币,因此,横坐标翻转次数和纵坐标翻转次数均为奇数时,总翻转次数才为奇数次。

  3、接下来我们需要考虑,哪些数有奇数个约数呢?答案是完全平方数。它为 1,4,9,16,25,36...... 即n的2次方,n为从1开始的正整数。

    从题目中得知,此时是一个 n * m 的矩阵,行号和列号都是从1开始。因此我们需要解决 1 到 n 之间完全平方数个数的问题。方法是求出sqrt(n),然后对它取整,即 1 - n 之间总共由于 (int)(sqrt(n)) 个完全平方数。因此,反面朝上硬币的个数为横纵坐标完全平方数个数相乘,即 (int)((sqrt(n)) * (sqrt(m))) 。

  4、由于此题的数据是超大规模的。因此,我们需要解决大数开方、大数相乘和大数比较等问题。

    通常使用 String 来接受键盘输入大数,因为它的长度比较容易控制。而使用 java.math.BigInteger 包中的 BigInteger 类来存储大数据。它的原则是,只要计算机有足够的的内存,它就能存储多长位数的数。

   大数开方: 牛顿逼近法。

        如果一个数的位数为偶数,那么这个数的方根就有 n/2 位,如果一个数的位数为奇数,这个数的方根就有 n/2 + 1 位。

        比如 num=1000 ,那么它的位数为 4 ,即方根就有 2 位。我们从方根的最高位进行枚举。

          先枚举出它的十位:

            10 * 10 = 100 < 1000

            20 * 20 = 400 < 1000

            30 * 30 = 900 < 1000

            40 * 40 = 1600 > 1000

          则这个根的十位为 3 。

          再枚举它的个位:

            31 * 31 = 961 < 1000

            32 * 32 = 1024 > 1000

          则这个根的个位为 1 。即这个根为 31 。

   大数相乘: 调用 java.math.* 包中的 multiply 方法。比如 bigNum1.multiply(bigNum2)

   大数比较: 调用 java.math.* 包中的 compareTo 方法,随第一个参数小于,等于或大于第二个参数返回负整数、零或正整数。比如 "2".compareTo ("3")

示例代码:

 1 import java.io.BufferedReader;
 2 import java.io.IOException;
 3 import java.io.InputStreamReader;
 4 import java.math.BigInteger;
 5 import java.util.Arrays;
 6
 7 public class Main {
 8     public static void main(String[] args) throws IOException {
 9         BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
10         String[] str = br.readLine().split(" ");
11         String n =     str[0];
12         String m =     str[1];
13         BigInteger answer = (bigSqrt(n)).multiply(bigSqrt(m));   //sqrt(n) * sqrt(m)  1-n之间的完全平方数的个数 * 1-m之间完全平方数的个数
14         System.out.println(answer);
15     }
16     //  求1 - num 之间完全平方数的个数
17     private static BigInteger bigSqrt(String num) {
18         int length = num.length();     //被开方数的位数
19         int sqrt_len = 0;            //开方数的位数
20         if(length % 2 == 0){
21             sqrt_len = length / 2;
22         }else{
23             sqrt_len = length / 2 + 1;
24         }
25         BigInteger beSqrtNum = new BigInteger(num);
26         char[] ch = new char[sqrt_len];            //记录开方数,开房数在数组中逆序存放
27         Arrays.fill(ch, ‘0‘);                      //将ch数组初始化为‘0‘
28         for(int i = 0; i < sqrt_len; i++){         //从开房数的最高位开始计算,使 每一位都转化为 开方数的平方且不大于被开方数
29             for(char j = ‘1‘; j <= ‘9‘; j++ ){
30                 ch[i] = j;
31                 String s = String.valueOf(ch);
32                 BigInteger sqrtNum = new BigInteger(s);
33                 BigInteger squareNum = sqrtNum.multiply(sqrtNum);
34                 if(squareNum.compareTo(beSqrtNum) == 1){     //大数比较问题
35                     ch[i] -= 1;
36                     break;
37                 }
38             }
39         }
40         return new BigInteger(String.valueOf(ch));
41     }
42 }
时间: 2024-10-05 17:14:30

蓝桥杯 历届试题 PREV-34 矩阵翻硬币的相关文章

蓝桥杯 历届试题 题目总结

后天就是蓝桥杯省赛了,今天总结一下这段时间做的蓝桥杯历届试题,还是一个一个题目的来吧!!!!!! 1,历届试题 矩阵翻硬币 这个题目说真的,我不会,在网上看了某神牛的题解答案为 ans=sqrt(n)*sqrt(m),具体怎么证明的我也不知道 2,历届试题 兰顿蚂蚁 这个题目怎么说呢,应该是送分题,直接模拟就可以了,这里就不说了. 3, 历届试题 分糖果 这个题目好像之前在哪里做过,也是一道模拟题,弄两个数组搞一下就可以了 下面是代码 #include<bits/stdc++.h> using

蓝桥杯历届试题 地宫取宝 dp or 记忆化搜索

问题描述 X 国王有一个地宫宝库.是 n x m 个格子的矩阵.每个格子放一件宝贝.每个宝贝贴着价值标签. 地宫的入口在左上角,出口在右下角. 小明被带到地宫的入口,国王要求他只能向右或向下行走. 走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,小明就可以拿起它(当然,也可以不拿). 当小明走到出口时,如果他手中的宝贝恰好是k件,则这些宝贝就可以送给小明. 请你帮小明算一算,在给定的局面下,他有多少种不同的行动方案能获得这k件宝贝. 输入格式 输入一行3个整数,用空格分开:n

蓝桥杯-历届试题之大臣的旅费

历届试题 大臣的旅费 时间限制:1.0s   内存限制:256.0MB 问题描述 很久以前,T王国空前繁荣.为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市. 为节省经费,T国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大城市都能从首都直接或者通过其他大城市间接到达.同时,如果不重复经过大城市,从首都到达每个大城市的方案都是唯一的. J是T国重要大臣,他巡查于各大城市之间,体察民情.所以,从一个城市马不停蹄地到另一个城市成了J最常做的事情.他有一个钱袋,用于

蓝桥杯历届试题题解1

4月11日省赛,给自己加油! 矩阵翻硬币:给定n,m.这么大的数据很明显找规律....打表处理小数据,代码: int a[500][500]; int main(){ int n,m,ans; int i,j,k,l; while(scanf("%d%d",&n,&m)!=EOF){ memset(a,0,sizeof(a)); ans=0; for(i=1;i<=n;i++) for(j=1;j<=m;j++) for(k=1;k<=n;k++) f

蓝桥杯 历届试题 带分数 DFS最容易理解版,内有解析

历届试题 带分数 时间限制:1.0s   内存限制:256.0MB 问题描述 100 可以表示为带分数的形式:100 = 3 + 69258 / 714. 还可以表示为:100 = 82 + 3546 / 197. 注意特征:带分数中,数字1~9分别出现且只出现一次(不包含0). 类似这样的带分数,100 有 11 种表示法. 输入格式 从标准输入读入一个正整数N (N<1000*1000) 输出格式 程序输出该数字用数码1~9不重复不遗漏地组成带分数表示的全部种数. 注意:不要求输出每个表示,

蓝桥杯 历届试题 连号区间数

历届试题 连号区间数 时间限制:1.0s   内存限制:256.0MB 问题描述 小明这些天一直在思考这样一个奇怪而有趣的问题: 在1~N的某个全排列中有多少个连号区间呢?这里所说的连号区间的定义是: 如果区间[L, R] 里的所有元素(即此排列的第L个到第R个元素)递增排序后能得到一个长度为R-L+1的"连续"数列,则称这个区间连号区间. 当N很小的时候,小明可以很快地算出答案,但是当N变大的时候,问题就不是那么简单了,现在小明需要你的帮助. 输入格式 第一行是一个正整数N (1 &

蓝桥杯 历届试题 斐波那契

困扰我N天的一题,今天终于解决了.话不多说,直接上题. 问题描述 斐波那契数列大家都非常熟悉.它的定义是: f(x) = 1 .... (x=1,2) f(x) = f(x-1) + f(x-2) .... (x>2) 对于给定的整数 n 和 m,我们希望求出: f(1) + f(2) + ... + f(n) 的值.但这个值可能非常大,所以我们把它对 f(m) 取模. 公式如下 但这个数字依然很大,所以需要再对 p 求模. 输入格式 输入为一行用空格分开的整数 n m p (0 < n, m

蓝桥杯 历届试题 大臣的旅费 DFS两次

历届试题 大臣的旅费 时间限制:1.0s   内存限制:256.0MB 问题描述 很久以前,T王国空前繁荣.为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市. 为节省经费,T国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大城市都能从首都直接或者通过其他大城市间接到达.同时,如果不重复经过大城市,从首都到达每个大城市的方案都是唯一的. J是T国重要大臣,他巡查于各大城市之间,体察民情.所以,从一个城市马不停蹄地到另一个城市成了J最常做的事情.他有一个钱袋,用于

蓝桥杯 历届试题 地宫取宝 【记忆化搜索】

历届试题 地宫取宝 时间限制:1.0s   内存限制:256.0MB 问题描述 X 国王有一个地宫宝库.是 n x m 个格子的矩阵.每个格子放一件宝贝.每个宝贝贴着价值标签. 地宫的入口在左上角,出口在右下角. 小明被带到地宫的入口,国王要求他只能向右或向下行走. 走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,小明就可以拿起它(当然,也可以不拿). 当小明走到出口时,如果他手中的宝贝恰好是k件,则这些宝贝就可以送给小明. 请你帮小明算一算,在给定的局面下,他有多少种不同的