您的位置:首页 > 编程语言 > Java开发

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

2016-03-17 22:01 344 查看
小明先把硬币摆成了一个n行m列的矩阵。

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


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


其中i和j为任意使操作可行的正整数,行号和列号都是从1开始。


当小明对所有硬币都进行了一次Q操作后,他发现了一个奇迹——所有硬币均为正面朝上。


小明想知道最开始有多少枚硬币是反面朝上的。于是,他向他的好朋友小M寻求帮助。

聪明的小M告诉小明,只需要对所有硬币再进行一次Q操作,即可恢复到最开始的状态。然而小明很懒,不愿意照做。于是小明希望你给出他更好的方法。帮他计算出答案。


【数据格式】

输入数据包含一行,两个正整数nm,含义见题目描述。

输出一个正整数,表示最开始有多少枚硬币是反面朝上的。


【样例输入】

23


【样例输出】

1


【数据规模】

对于10%的数据,n、m<=10^3;

对于20%的数据,n、m<=10^7;

对于40%的数据,n、m<=10^15;


对于10%的数据,n、m<=10^1000(10的1000次方)

11->1

12->1

13->1

14->2

15->2

16->2

17->2

18->2

19->3

110->3

111->3

112->3

113->3

114->3

115->3

116->4

117->4

118->4

119->4

...

...

规律就是,当x固定为1时,按照3个1,5个2,7个3,9个4一直走下去.

yf(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时

xf(x):

[1--3]....1

[4--8]....2

[9--15]....3

[16--24]....4

[25--35]....5

[36--48]....6

...

...

好巧啊,与x固定时一样.

然后经过测试,f(x)*f(y)为答案.....

输入:

44-->4(2*2)

1625-->20(4*5)

100100-->100(10*10)

importjava.math.BigDecimal;
importjava.math.BigInteger;
importjava.math.MathContext;
importjava.math.RoundingMode;
importjava.util.Scanner;

publicclasstest{

publicstaticvoidmain(String[]args){
//想看那个方法就直接调用哪个
//FangFaOne();
//FangFaTwo();
}

//方法一:拼命算,最笨的方法,但是当数据过大时会,没法储存
publicstaticvoidFangFaOne(){
Scannerin=newScanner(System.in);
while(in.hasNext()){
intx=in.nextInt();
inty=in.nextInt();
//用boolean二维数组储存矩阵,从[1][1]开始
boolean[][]grap=newboolean[x+1][y+1];
for(inti=1;i<=x;i++){
for(intj=1;j<=y;j++){
//全部的置为正面
grap[i][j]=true;
}
}
intnum=1;
//有几枚硬币就循环几次
while(num<=x*y){
//取x_num,表示在第几行,y_num表示第几列
intx_num=num/y+1;
inty_num=num%y;
//在行末的时候需要格外处理,例如num=3,表示第三枚硬币在1行3列
if(num%y==0)
{
x_num=num/y;
y_num=y;
}

//Q操作
for(inti=1;i*x_num<=x;i++){
for(intj=1;j*y_num<=y;j++){
grap[i*x_num][j*y_num]=!grap[i*x_num][j*y_num];
}
}
//处理下一枚硬币
num+=1;
}

//统计false(反面)的数量
intsum=0;
for(inti=1;i<=x;i++){
for(intj=1;j<=y;j++){
if(!grap[i][j]){
sum+=1;
}
}
}
System.out.println(sum);
}
}

//方法二:将1的规律总结,用大数处理
publicstaticvoidFangFaTwo(){
Scannerin=newScanner(System.in);
while(in.hasNext()){
//因为开方涉及小数,所以采用BigDecimal,BIG小数
BigDecimalx=in.nextBigDecimal();
BigDecimaly=in.nextBigDecimal();
BigDecimaldealX=deal(x);
BigDecimaldealY=deal(y);
//大数乘操作
System.out.println(dealX.multiply(dealY));
}
}

publicstaticBigDecimaldeal(BigDecimalx){
//+1操作
x=x.add(BigDecimal.valueOf(1));
//开方操作,太大需要重新定义大数的格式
MathContextmc=newMathContext(1000,RoundingMode.HALF_DOWN);
x=newBigDecimal(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);
returnx;
}
}


貌似是官方代码

importjava.math.BigInteger;
importjava.util.Scanner;
publicclasstest2{

privatestaticBigIntegersqrt(BigIntegern){
BigIntegertwo=BigInteger.valueOf(2);
BigIntegerprv=n.divide(two);
BigIntegernow=prv.add(n.divide(prv)).divide(two);
while(prv.compareTo(now)>0){
prv=now;
now=prv.add(n.divide(prv)).divide(two);
}
returnnow;
}
publicstaticvoidmain(String[]args){
Scannersc=newScanner(System.in);
BigIntegern=sqrt(sc.nextBigInteger());
BigIntegerm=sqrt(sc.nextBigInteger());
System.out.println(n.multiply(m));
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: