问题描述
小明先把硬币摆成了一个 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();
}
}