java大數詳解
引論
在演算法競賽中我們經常遇到大數問題,例如求一個很大的斐波那契數。住在這種情況下我們用常規解法(使用long long或long long int)肯定是不行的,而我們自己寫一個大數的演算法又過於麻煩且易於出錯,在這種情況下使用java中自帶的大數類是我們最好的選擇
介紹
java中用於操作大數的類主要有兩個,一個是BigInteger,代表大整數類用於對大整數進行操作,另一個是BigDecimal,代表大浮點型。因為這兩種類的使用方法是一樣的且通常情況下我們處理的資料是整數,所以下面我們以BigInteger為例進行講解
基本用法
1、新建一個值為123的大整數物件
BigInteger a=new BigInteger(“123”); //第一種,引數是字串
BigInteger a=BigInteger.valueOf(123); //第二種,引數可以是int、long
2、大整數的四則運算
a. add(b); //a,b均為BigInteger型別,加法
a.subtract(b); //減 法
a.divide(b); //除法
a.multiply(b); //乘法
3、大整數比較大小
a.equals(b); //如果a、b相等返回true否則返回false
a.compareTo(b); //a小於b返回-1,等於返回0,大於返回1
4、常用方法
a.mod(b); //求餘
a.gcd(b); //求最大公約數
a.max(b); //求最大值
a.min(b); //求最小值
5、BigInteger中的常數
BigInteger.ZERO //大整數0
BigInteger.ONE //大整數1
BigInteger.TEN //大整數10
6、求大整數的位數
//先轉換成字串在求字串的長度
a.toString().length(); //a的型別為BigInteger
輸入框架
場景一
不斷讀入資料直至檔案尾,或者說有多組測試用例以EOF為結束標誌
Scanner cin = new Scanner(System.in); //相當於C++中的cin,只不過這個cin需要自己建立 while(cin.hasNext()){ //等同於!=EOF BigInteger a; a = cin.nextBigInteger(); //讀入一個BigInteger; System.out.println(a); //輸出a並換行 }
場景二
輸入一個整數T,代表有T組測試樣例
Scanner cin = new Scanner(System.in);
int T = cin.nextInt();
while (T-- > 0) {
System.out.println(T);
}
注意
使用java大數類解決問題時我們需要注意兩個方面
1、不能有包名,也就是說我們要把主類放到預設的包裡,如果你的程式碼裡出現形如package cn.gov.test;這樣的程式碼你很有可能會收穫到RE
2、提交的類的類名必須為Main,如果是其他的名字你有可能收穫到CE也有可能收穫到WA(例如UVA)
3、不要想當然的認為執行了a.add(b)之後a的值會發生改變,這句程式碼只是求值而已,相當於a + b,計算了a + b之後a的值會改變嗎?當然不會!所以我們要想達到 a = a + b的效果需要寫a = a.add(b)
例題
光說不練假把式,學習了理論之後我們更需要編碼練習,下面是我挑選的幾個例題,希望能幫助到你
1、A == B ?
題目描述:輸入兩個非常大的數A和B,判斷A是否等於B,如果相等輸出YES,否則輸出NO
分析:這個題在hdu上實際上並沒有給出範圍,WA了之後才知道這是道大數題,因為僅僅涉及到輸入、比較和輸出,所以非常適合用作大數的入門題
注意:這裡只是說給出兩個數A和B,並沒有說是兩個整數,所以應該採用BigDecimal
參考程式碼
import java.math.BigDecimal;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
BigDecimal a, b;
Scanner cin = new Scanner(System.in);
while (cin.hasNext()) {
a = cin.nextBigDecimal();
b = cin.nextBigDecimal();
if (a.compareTo(b) == 0) System.out.println("YES");
else System.out.println("NO");
}
}
}
2、大整數加法
題目描述:求兩個不超過200位的非負整數的和。
分析:也是非常簡單的入門題,直接輸入後呼叫BigInteger自帶的方法add即可
參考程式碼
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
BigInteger a,b;
Scanner cin = new Scanner(System.in);
a = cin.nextBigInteger();
b = cin.nextBigInteger();
System.out.println(a.add(b));
}
}
3、大數階乘
題目描述:給你一個n,計算n的階乘,但是n很可能比較大
分析:因為m很小隻有5000所以我們可以從1開始打一個階乘表,這樣的話當有輸入的時候我們就可以用O(1)的複雜度解決它
參考程式碼
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
BigInteger f[] = new BigInteger[5500];
f[0] = f[1] = BigInteger.ONE;
for (int i = 2; i <= 5000; ++i) {
f[i] = f[i - 1].multiply(BigInteger.valueOf(i));
}
Scanner cin = new Scanner(System.in);
while (cin.hasNext()) {
int m = cin.nextInt();
System.out.println(f[m]);
}
}
}
4、大菲波數
題目描述:計算第n項Fibonacci數值,n可能比較大
分析:這個題與上一題一樣,需要先打表在輸出
參考程式碼
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner cin = new Scanner(System.in);
BigInteger[] nums = new BigInteger[1010];
nums[1] = new BigInteger("1");
nums[2] = new BigInteger("1");
for(int i = 3; i <= 1000; i++)
nums[i] = nums[i - 1].add(nums[i - 2]);
int T = cin.nextInt();
while(T > 0)
{
T--;
int n = cin.nextInt();
System.out.println(nums[n]);
}
}
}
5、A/B
題目描述:要求(A/B)%9973,但由於A很大,我們只給出n(n=A%9973)(我們給定的A必能被B整除,且gcd(B,9973) = 1)。
分析:最容易想到的方法莫過於讓n一直加9973加到n Mod b == 0,不過很可惜這樣做會超時的;所以我們換一種思路,因為a一定能被b整除,所以a一定是b的倍數,於是我們讓a = b * i(i= 1,2,3···)直到a Mod b == n;此時得到大整數a直接用題目中給的公式就能將正確答案做出來
參考程式碼
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner cin = new Scanner(System.in);
int T = cin.nextInt();
while(T > 0)
{
T--;
BigInteger a = cin.nextBigInteger();
BigInteger b = cin.nextBigInteger();
BigInteger d = new BigInteger("9973");
BigInteger z = new BigInteger("0");
for(BigInteger i = new BigInteger("1"); ; i = i.add(new BigInteger("1")))
{
BigInteger c = b.multiply(i);
if(c.mod(d).compareTo(a) == 0)
{
System.out.println(i.mod(d));
break;
}
}
}
}
}