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


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值