深度优先

这个家伙好懒,除了文章什么都没留下

0%

【算法】矩阵翻硬币(大数开方)

历届试题 矩阵翻硬币

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

问题描述

小明先把硬币摆成了一个 n 行 m 列的矩阵。

随后,小明对每一个硬币分别进行一次 Q 操作。

对第x行第y列的硬币进行 Q 操作的定义:将所有第 ix 行,第 jy 列的硬币进行翻转。

其中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次方)。

这个题最先是想着通过模拟翻硬币的那个过程做的,但是提交后数据量非常大只过了10%的数据,然后打印出翻硬币的情况,从中发现了规律。

最终,归结为n开方数*m的开方数即为最终输出的结果。燃鹅,n和m都是非常的数,这就涉及到大数开方的算法。

模拟翻硬币的过程代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import java.util.Scanner;

public class 矩阵翻硬币 {

public static void main(String[] args) {

Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int m=sc.nextInt();

int count=getFan(n+1,m+1);
System.out.println(count);
}
private static int getFan(int n,int m) {

int[][] data=new int[n][m];

for (int i = 1; i < n+1; i++) {
for (int j = 1; j < m+1; j++) {
int x=i,y=j;
for (int k = 1; k*x < n; k++) {
for (int h = 1; h*y < m ; h++) {
if(data[k*x][h*y]==0)
data[k*x][h*y]=1;
else
data[k*x][h*y]=0;
}
}
}
}
int count=0;
for (int i = 1; i < n; i++) {
for (int j = 1; j < m; j++) {
System.out.print(data[i][j]+",");
if(data[i][j]==1)
count++;
}
System.out.println();
}
return count;
}
}

找到规律后用n开方*m开方:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import java.math.BigInteger;
import java.util.Scanner;

public class 大数开方2 {

public static void main(String[] args) {

Scanner sc=new Scanner(System.in);

BigInteger n=sc.nextBigInteger();
BigInteger m=sc.nextBigInteger();

System.out.println(sqrt(n).multiply(sqrt(m)));

}

private static BigInteger sqrt(BigInteger n) {
BigInteger a;
BigInteger b;

a=BigInteger.TEN.pow((int)n.toString().length()/2);
b=n.divide(a);

while(!(a.equals(b)||a.equals(b.add(new BigInteger("-1")))||b.equals(a.add(new BigInteger("-1"))))){
a=a.add(b).divide(new BigInteger("2"));//a=(a+b)/2
b=n.divide(a);
}

if (a.equals(b.add(new BigInteger("-1")))) {
return a;
}
return b;
}
}

大数开方的算法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import java.math.BigInteger;
import java.util.Scanner;

public class 大数开方3 {
public static BigInteger getSqrt(BigInteger n){
BigInteger a,b;
BigInteger cs=new BigInteger("2");
int len=n.toString().length();
a=BigInteger.TEN.pow(len/2);
b=n.divide(a);
int k=1;
while(k==1){
if(a.equals(b)||a.equals(BigInteger.ONE.add(b))||b.equals(BigInteger.ONE.add(a))){
k=0;
}else{
a=a.add(b).divide(cs);
b=n.divide(a);
}
}
return a;
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
for (int i = 1; i < 20; i++) {
BigInteger n=BigInteger.valueOf(i);
System.out.println(i+"开方为:"+getSqrt(n));
}
//BigInteger n=sc.nextBigInteger();
//System.out.println(getSqrt(n));
}

}