https://www.luogu.org/problemnew/show/P2152
一开始不知道Java可以有gcd,手写了个辗转相除法。
发现Number类在参数传递中传的并非是引用!
最主要要解决的是MLE的问题,经查询得知System.gc()方法可以手动回收内存。
但是它慢得离谱!
我们考虑使用一个cnt计数器来平衡空间和时间的花费。经过试验cnt每800回收一次内存最终可以使花费内存到达32MB。
接近原本内存消耗的1/3!
至于为什么是模800……模200的时候TLE了,瞎蒙一个800。
估计是gcd的复杂度是对数级别的,那么模800大概会回收数十次内存。
这个实现太蠢了其实大数也有mod的……数学mod是mod,计算机%是remainder。减少了很多中间步骤使得时间和空间都有显著提升。
另外。其实也有pow和modPow,甚至有sqrt以及大素数素性测试!
import java.util.*; import java.math.*; public class Main { public static void main(String args[]) { Scanner sc=new Scanner(System.in); BigInteger A=sc.nextBigInteger(); BigInteger B=sc.nextBigInteger(); sc.close(); System.gc(); BigInteger T1; int cnt=0; while(B.compareTo(BigInteger.ZERO)!=0) { T1=B; B=A.subtract(A.divide(B).multiply(B)); A=T1; cnt++; if(cnt%800==0) { T1=null; System.gc(); } } T1=null; B=null; System.out.println(A); } }
而模600的话则接近TLE了。
估计模5000应该是比较好的平衡点?在有限的空间中尽可能缩短时间。空间消耗达到80MB,但是速度快至5秒!(模800是大约8秒)
最后,原来BigInteger有内置的gcd方法!
快至2秒,内存消耗17MB!
import java.util.*; import java.math.*; public class Main { public static void main(String args[]) { Scanner sc=new Scanner(System.in); BigInteger A=sc.nextBigInteger(); BigInteger B=sc.nextBigInteger(); System.out.println(A.gcd(B)); sc.close(); } }