洛谷

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();
    }
}
原文地址:https://www.cnblogs.com/Yinku/p/10660370.html