FZU 1759 Super A^B mod C (快速幂+指数循环节)

本文介绍了一种解决大数幂取模问题的有效算法,并通过示例代码详细展示了如何运用快速幂运算及欧拉定理来高效计算A^B mod C的结果。特别地,对于非常大的指数B,文章提出了一种利用指数循环节公式的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem 1759 Super A^B mod C

Accept: 602 Submit: 2024
Time Limit: 1000 mSec Memory Limit : 32768 KB

Problem Description

Given A,B,C, You should quickly calculate the result of A^B mod C. (1<=A,C<=1000000000,1<=B<=10^1000000).

Input

There are multiply testcases. Each testcase, there is one line contains three integers A, B and C, separated by a single space.

Output

For each testcase, output an integer, denotes the result of A^B mod C.

Sample Input

3 2 42 10 1000

Sample Output

124

Source

FZU 2009 Summer Training IV--Number Theory 

1<=B<=10^1000000,看起来数据很大,unsigned long long 都无法直接存储。
指数循环节公式:a^b%c = a^( b%phic+phic )%c,具体证明过程http://hi.baidu.com/aekdycoin/item/e493adc9a7c0870bad092fd9
其中phic为c的欧拉函数,详见:http://baike.baidu.com/view/107769.htm?fr=aladdin
注:使用指数循环节公式时,需要b>c
因此判断b的大小,如果在10e10范围内,可直接用快速幂

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <sstream>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <ctime>
using namespace std;
typedef unsigned long long LL;
int geteular(int n){
	int ret = 1,i;
	for(i = 2;i*i<=n;i++){
		if(n%i==0){
			n/=i;
			ret*=i-1;
		}
	while(n%i==0){
		n/=i;
		ret*=i;
	}
}
	if(n>1){
	ret*=n-1;
}
	return ret;
}
LL mul(LL a,LL b,LL c){
	LL ans = 0,temp = a%c;
	while(b){
	//	cout<<"ans"<<endl;
		if(b&0x1){
			if((ans+=temp)>=c){
				ans-=c;
			}
	}		
			if((temp<<=1)>=c){
				temp-=c;
			}	
			b>>=1;
	}
	return ans;
}
LL modPow(LL a,LL b,LL m){
	LL ret = 1;
	while(b){
//		cout<<"ret"<<endl;
		if(b&1){
		ret = mul(ret,a,m);	
		}//ret = ret*a%m;
		//a = a*a%m;
		a = mul(a,a,m);
		b>>=1;
	}
	return ret;
}
char b[1100000];
int main() {
	// a^b%c = a^( b%phic+phic )%c;
	LL a,c;
	while(scanf("%I64d%s%I64d",&a,&b,&c)!=EOF){
//		LL sum = modPow(a,b,c);
//		printf("%I64d\n",sum);
//	}
//	
	int n = strlen(b);
	if(n<=10){
		LL numb = 0;
		for(int i = 0;i<n;i++){
			numb = numb*10 + b[i] - '0';
		}
		LL sum = modPow(a,numb,c);
		printf("%I64d\n",sum);
	}else{
		LL phic = geteular(c);
		LL numb = 0;
		for(int i = 0;i<n;i++){
			numb = numb%phic;
			numb = numb*10 + b[i] - '0';
		}
		numb += phic;
		LL sum = modPow(a,numb,c);
		printf("%I64d\n",sum);
	}
}
	return 0;	
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值