小明先把硬币摆成了一个 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;
1 1 ->1
1 2 ->1
1 3 ->1
1 4 ->2
1 5 ->2
1 6 ->2
1 7 ->2
1 8 ->2
1 9 ->3
1 10 ->3
1 11 ->3
1 12 ->3
1 13 ->3
1 14 ->3
1 15 ->3
1 16 ->4
1 17 ->4
1 18 ->4
1 19 ->4
...
...
规律就是,当x固定为1时,按照3个1,5个2,7个3,9个4一直走下去.
y f(x):
[1 -- 3] .... 1
[4 -- 8] .... 2
[9 -- 15] .... 3
[16 -- 24] .... 4
[25 -- 35] .... 5
[36 -- 48] .... 6
...
...
好巧啊,(a) -- (b)...i
b = (i+1)*(i+1)-1
a=i*i
导出公式
f(y) = ( √(y+1) ) - 1 算式写出后用进一法取整.
算是完成一半
当y固定为1时
x f(x):
[1 -- 3] .... 1
[4 -- 8] .... 2
[9 -- 15] .... 3
[16 -- 24] .... 4
[25 -- 35] .... 5
[36 -- 48] .... 6
...
...
好巧啊,与x固定时一样.
然后经过测试,f(x)*f(y)为答案.....
输入:
4 4 --> 4 (2*2)
16 25 --> 20 (4*5)
100 100 --> 100 (10*10)
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.Scanner;
public class test {
public static void main(String[] args) {
//想看那个方法就直接调用哪个
//FangFaOne();
//FangFaTwo();
}
//方法一:拼命算,最笨的方法,但是当数据过大时会,没法储存
public static void FangFaOne(){
Scanner in = new Scanner(System.in);
while(in.hasNext()){
int x = in.nextInt();
int y = in.nextInt();
//用boolean二维数组储存矩阵,从[1][1]开始
boolean[][] grap = new boolean[x+1][y+1];
for(int i=1;i <= x;i++){
for(int j=1;j<=y;j++){
//全部的置为正面
grap[i][j]=true;
}
}
int num=1;
//有几枚硬币就循环几次
while(num<=x*y){
//取x_num,表示在第几行,y_num表示第几列
int x_num = num/y+1;
int y_num = num%y;
//在行末的时候需要格外处理,例如num=3,表示第三枚硬币在1行3列
if(num%y == 0)
{
x_num =num/y;
y_num = y;
}
//Q操作
for(int i = 1;i * x_num <= x;i++){
for(int j= 1;j *y_num <= y;j++){
grap[i * x_num][j *y_num]=!grap[i * x_num][j *y_num];
}
}
//处理下一枚硬币
num+=1;
}
//统计false(反面)的数量
int sum = 0;
for(int i=1;i <= x;i++){
for(int j=1;j<=y;j++){
if(!grap[i][j]){
sum+=1;
}
}
}
System.out.println(sum);
}
}
//方法二:将1的规律总结,用大数处理
public static void FangFaTwo() {
Scanner in = new Scanner(System.in);
while(in.hasNext()){
//因为开方涉及小数,所以采用BigDecimal,BIG小数
BigDecimal x = in.nextBigDecimal();
BigDecimal y = in.nextBigDecimal();
BigDecimal dealX = deal(x);
BigDecimal dealY = deal(y);
//大数乘操作
System.out.println(dealX.multiply(dealY));
}
}
public static BigDecimal deal(BigDecimal x){
//+1操作
x = x.add(BigDecimal.valueOf(1));
//开方操作,太大需要重新定义大数的格式
MathContext mc = new MathContext(1000,RoundingMode.HALF_DOWN);
x = new BigDecimal(Math.sqrt(x.doubleValue()),mc);
//-1操作
x = x.add(BigDecimal.valueOf(-1));
//进一法取整,0表示小数有零位,
//BigDecimal.ROUND_UP表示取整类型,是进一法(向上进)
//BigDecimal.ROUND_DOWN表示取整类型,是去一法(向下进)
x = x.setScale(0, BigDecimal.ROUND_UP);
return x;
}
}
貌似是官方代码
import java.math.BigInteger;
import java.util.Scanner;
public class test2 {
private static BigInteger sqrt(BigInteger n) {
BigInteger two = BigInteger.valueOf(2);
BigInteger prv = n.divide(two);
BigInteger now = prv.add(n.divide(prv)).divide(two);
while (prv.compareTo(now) > 0) {
prv = now;
now = prv.add(n.divide(prv)).divide(two);
}
return now;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
BigInteger n = sqrt(sc.nextBigInteger());
BigInteger m = sqrt(sc.nextBigInteger());
System.out.println(n.multiply(m));
}
}