问题描述
小明先把硬币摆成了一个 n 行 m 列的矩阵。
随后,小明对每一个硬币分别进行一次 Q 操作。
对第x行第y列的硬币进行 Q 操作的定义:将所有第 i*x 行,第 j*y 列的硬币进行翻转。
其中i和j为任意使操作可行的正整数,行号和列号都是从1开始。
当小明对所有硬币都进行了一次 Q 操作后,他发现了一个奇迹——所有硬币均为正面朝上。
小明想知道最开始有多少枚硬币是反面朝上的。于是,他向他的好朋友小M寻求帮助。
聪明的小M告诉小明,只需要对所有硬币再进行一次Q操作,即可恢复到最开始的状态。然而小明很懒,不愿意照做。于是小明希望你给出他更好的方法。帮他计算出答案。
随后,小明对每一个硬币分别进行一次 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次方)。
对于20%的数据,n、m <= 10^7;
对于40%的数据,n、m <= 10^15;
对于10%的数据,n、m <= 10^1000(10的1000次方)。
解析:
1.每个硬币被翻转的次数为其横坐标的约数个数 * 其纵坐标的约数个数。
2.如果一个硬币被翻转奇数次,说明其初始状态为反面朝上。
3.因为奇数 * 奇数 = 奇数 , 则需要找出约数为奇数的坐标。
4.如果一个数的约数个数为奇数,说明它是一个完全平方数。
5.在m的范围内,完全平方数的个数为sqrt(m)个。
6.在矩阵中,有sqrt(a)行是奇数,sqrt(b)列是奇数。
7.则所有正面朝上的硬币个数为sqrt(a) * sqrt(b)。
代码:
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner input = new Scanner(System.in); String strA = input.next(); String strB = input.next(); char[] a = strA.toCharArray(); char[] b = strB.toCharArray(); read(multiply(sqrt(a),sqrt(b))); input.close(); } // 大数相乘 private static int[] multiply(char[] a, char[] b) { int[] c = new int[a.length + b.length]; for (int i = a.length - 1; i >= 0; i--) { for (int j = b.length - 1; j >= 0; j--) { c[(a.length - 1) + (b.length - 1) - (i + j)] += (a[i] - '0') * (b[j] - '0'); } } for (int i = 0; i < c.length - 1; i++) { c[i + 1] += c[i] / 10; c[i] = c[i] % 10; } int i; for(i = c.length-1;i>=0 && c[i] == 0;i--); int []d = new int[i+1]; int j = 0; for(;i >= 0;i--) d[j++] = c[i]; return d; } // 大数开方 private static char[] sqrt(char a[]) { int len = (a.length & 1) == 1 ? a.length / 2 + 1 : a.length / 2; char[] c = new char[len]; for(int i = 0;i < c.length;i++) c[i] = '0'; for (int i = 0; i < len; i++) { for (char j = '0'; j <= '9'; j++) { c[i] = j; int[] tmp = multiply(c, c); int t = compare(tmp,a); if (t == 0) break; if (t == 1) { c[i] -= 1; break; } } } return c; } // 大数比较 private static int compare(int a[], char b[]) { if (a.length < b.length) return -1; if (a.length > b.length) return 1; for (int i = 0; i < a.length; i++) { if (a[i] == (int) (b[i] - '0')) continue; if (a[i] > (int) (b[i] - '0')) return 1; else return -1; } return 0; } // 输出大数 private static void read(int [] c) { for (int i = 0; i < c.length; i++) System.out.print(c[i]); System.out.println(); } }