矩阵翻硬币(2014年蓝桥杯Java-B组第十题)

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



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));
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值