WOJ中大整數冪乘的處理(BigInteger/字符串數組表示/冪乘法)

        最近看《java核心技術卷I》,開篇幾章就提到了BigInteger類,查了下相關文檔,在不考慮其效率的時候,用作處理WOJ中的大整數還是挺有效的(BigInteger類可以存儲任意大小的數)。

先鏈接兩個比較好的博文:淺談 BigInteger     再談 BigInteger - 使用快速傅里葉變換

示例幾個題目:

Problem 1142 - Half of and a Half         Problem 1302 - Raising Modulo Numbers             Problem 1315 - 高級機密


一、用JAVA BigInteger類處理上述題目

T1142 的意思其實很簡單,由數列規律可以退出  a[n] = 2*a[n-1] +1 ,且a[0] = 1, 那麼很容易推出 a[n]=2^(n+1)-1; 題目中 n的取值範圍是n<=1000,那麼用BigInteger實現就很簡單:

package T_1142;

import java.math.BigInteger;
import java.util.Scanner;

public class Main {
	public static void main(String[] args)
	{
		Scanner sc = new Scanner(System.in);		
		int n = 0;
		
		while(sc.hasNext())
		{
			BigInteger BigResult = BigInteger.valueOf(2);
			n = sc.nextInt();
			if(n < 0)
				return;
			else
			{
				BigResult = BigResult.pow(n+1);
				BigResult = BigResult.add(BigInteger.valueOf(-1));				
				System.out.println(BigResult);	
			}
		}
	}
}

  

    T1302 中沒有說Ai和Bi的取值範圍,H和M的取值範圍是 <=45000,用普通的數據類型肯定不能存儲。用BigInteger也很容易實現:

package T_1302;

import java.math.BigInteger;
import java.util.Scanner;

public class main {
	public static void main(String[] arg)
	{
		Scanner in = new Scanner(System.in);
		int T = in.nextInt();	
		
		int a[] = new int[45005];
		int b[] = new int[45005];
		
		while(T>0)
		{
			BigInteger m = BigInteger.valueOf(in.nextInt());
			int n = in.nextInt();		
			BigInteger result = BigInteger.valueOf(0);
			
			for(int i=0; i<n; i++)
			{
				a[i] = in.nextInt();
				b[i] = in.nextInt();
				BigInteger Big_a = BigInteger.valueOf(a[i]);
				BigInteger Big_b = BigInteger.valueOf(b[i]);
				Big_a = Big_a.modPow(Big_b, m);
				
				result = result.add(Big_a);
			}
			
			System.out.println(result.mod(m));
			
			T--;
		}		
	}
}

  T1315 中用BigInteger提交時,超時(不理解上一題提交時不會超時,估計是取摸運算時候,上題的M<=45000,本題C<=2^30):

package T_1315;

import java.util.*;
import java.math.*;

public class main{
	public static void main(String[] args)
	{
		Scanner in = new Scanner(System.in);
		int a = in.nextInt();
		int b = in.nextInt();
		int c = in.nextInt();
		
		while(!(a==0 && b==0 && c==0))
		{
			BigInteger Big_a = BigInteger.valueOf(a);
			BigInteger Big_b = BigInteger.valueOf(b);
			BigInteger Big_c = BigInteger.valueOf(c);
			BigInteger result = BigInteger.valueOf(0);
			
			if(c==0)
				result = Big_a.pow(b);
			else			
				result = Big_a.modPow(Big_b, Big_c);
			
			System.out.println(result);	
			
			 a = in.nextInt();
			 b = in.nextInt();
			 c = in.nextInt();			
		}
	}
}


二、字符串數組表示大整數冪乘

    T1142 由a[n] = 2*a[n-1]+1得知,採用字符串數組的形式表示 a[n] 數值的每一位,a[n]*2時只是將字符串數組的每一位轉化爲整數值乘2處理,注意進位:

/* Time: 2012.10.21
   Number: WOJ 1142
   Type: 大數值的處理 (用字符串表示大數值) 
*/

#include <stdio.h>
#include <stdlib.h>
#include <string>
using namespace std; 

int main()
{
	char max[1000]; 
	int N; 
	int i, j;
	int temp; 
	int carry; // 進位 
	
	while(scanf("%d", &N) != EOF)
	{
		memset(max, '\0' ,sizeof(max)); 
		max[0] = '1'; 
		for(i=N; i>0; i--)
		{
			carry = 0;
			j = 0; 
			while(max[j] != 0)
			{
				temp = (max[j] - '0')*2; 
				max[j] = (temp%10)+'0' + carry; 
				carry = temp/10;
				j++;			
			}
						
			if(carry != 0)
				max[j] = carry + '0'; 			 
			 
			max[0] += 1;
		} 
		
		for(i=strlen(max)-1; i>=0; i--)
		{
			j = max[i]-'0'; 
			printf("%d", j);
		}
		
		printf("\n"); 
	}
	
	system("pause");
	return 0;
} 


三、冪乘法求解大整數冪乘

T1315 採用冪乘法, 計算大數值: a^b%c 時,可以採用公式 :
當b是偶數時,a^b%c = (a^(b/2))^2%c = ((a^2%c)^b/2)%c; 那麼b/2可以設置爲循環迭代結構,算法複雜度是 O(log(b));
當b是奇數時,a^b%c = {[(a^(b/2))^2]*a}%c = {[((a^2%c)^b/2)]*a}%c,主要原因其實就是 b = 2*(b/2) + 1;   注意每次迭代時都要注意b/2的奇偶性;

#include <stdio.h>
#include <stdlib.h>

int main()
{

	long long int a,b,c;
	long long int ans;
	int flag = 0;

	while(scanf("%lld%lld%lld",&a,&b,&c)==3 &&(a!=0 || b!=0 || c!=0))
	{
		ans = 1;
	
		while(b>=1)
		{ 
	
			if(b%2==1) 
				ans = a*ans%c; 
			
			a=a*a%c;
			b=b/2;
		}
		
		printf("%lld\n", ans);
	}
	
	system("pause");
	return 0;

}

四、求100!中0的個數

         組合數學老師給的一個題目,之前做的時候採用的是字符串數組依次存儲計算結果,最後計算0的個數。《編程之美》有個更好的解法:對N!主要是將N!質因數分解,因爲只有2*5才能產生10即一個0,那麼就求分解後5的冪次方總和(該和小於2的冪次方和)。 詳見編程之美--N的階乘中末尾有幾個0


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章