蓝桥杯:矩阵翻硬币 java实现

10.矩阵翻硬币

  • 小明先把硬币摆成了一个 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

思路

  • 用题目中的操作只能过10%的数据.
  • 首先要理解Q操作的定义:将所有第i*x 行,第j*y 列的硬币进行翻转. 也就是说现在定位的硬币坐标是x,y, 是x的倍数的行都要翻, 是y的倍数的列也要翻.
  • 假设有9行9列的硬币, 对坐标(9,9)的硬币target进行分析. 第一行的硬币命中了target的行, 假如来到第一列, 那么target就要翻一下; 假如来到了第1行, 第3列, target也要翻一下.
  • 这么一来, 一个硬币就要翻 (x的因子数 * y的因子数) 那么多次
  • 如果一个数一共翻了奇数次, 它一开始就是反面朝上的.
  • 由于只有奇数相乘才能得到奇数. 所以要求x的因子数和y的因子数都必须是奇数.
  • 什么数的因子数是奇数? 只有平方数的因子数是奇数, 因为普通数的因子数都是一对一对的.
  • 所以现在的问题转化成求x中有多少个平方数y中有多少个平方数.
  • 平方数有: 1, 4, 9…
  • 根据数学规律, 求一个数包含多少个平方数只需要将该数开方后向下取整即可, 比如说10开方取整后得3, 它一共包含3个平方数.
  • 由于数据的取值范围是10^1000, 不能用已有的基本数据类型进行开放, 所以接下来的问题转化为如何对一个大数进行开方.
  • 首先要知道大数有多少位, 比如两位数16开方后得一位数4, 3位数100开方后得2位数10. 总结出结果是如果一个数的位数是偶数, 开方后得到的数的位数也是偶数, 如果是奇数, 得出的结果有原数位数 / 2 + 1 这么多位.
  • 知道结果有多少位后, 就可以试数了. 假设结果是3位, 先假设为000, 然后从头开始试100, 试110, 试111, 试112…直到得出平方数.
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		String n = sc.next();
		String m = sc.next();
		System.out.println(sqrt(n).multiply(sqrt(m)));
	}
	
	public static BigInteger sqrt(String num){
		int numLen = num.length();//要开方的数字位数
		int resLen = (numLen & 1) == 0 ? numLen / 2 : numLen / 2 + 1;//开方后数字的位数
		char[] arr = new char[resLen];//用于尝试结果的数组
		Arrays.fill(arr, '0');
		BigInteger target = new BigInteger(num);
		for(int pos = 0; pos < resLen; pos++){
			for(char i = '1'; i <= '9'; i++){
				arr[pos] = i;
				BigInteger pow = new BigInteger(String.valueOf(arr)).pow(2);
				if(pow.compareTo(target) == 1){
					arr[pos] -= 1;
					break;
				}
			}
		}
		return new BigInteger(String.valueOf(arr));
	}
}

猜你喜欢

转载自blog.csdn.net/weixin_41357767/article/details/88528530