FZU Problem 1759 Super A^B mod C

Problem 1759 Super A^B mod C

Accept: 1877 Submit: 6419 Time Limit: 1000 mSec Memory Limit : 32768 KB

img 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).

img Input

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

img Output

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

img Sample Input

3 2 4

2 10 1000

img Sample Output

1

24

img Source

FZU 2009 Summer Training IV–Number Theory

解决思路1

#include<iostream>
int main() {
	int A, C, ans;
	__int64 B, i;
	while (scanf("%d %I64d %d", &A, &B, &C) != EOF) {
		ans = A;
		for (i = 0; i < B-1; i++) {
			ans = (ans*A) % C;
		}
		printf("%d\n", ans);
	}
}

Time Limit Exceed

解决思路2

知识点一:快速幂

假设我们要求ab,按照朴素算法就是把a连乘b次,这样一来时间复杂度是O(b),即是O(n)级别。但快速幂能做到O(logn)的复杂度。

快速幂:

先上实现快速幂运算的具体代码:

int qsm(int a, int b)
{
	int ans = 1, base = a;
	while (b != 0) {
		if (b & 1 != 0) {
			ans *= base;
		}
		base *= base;
		b >>= 1;
	}
	return ans;
}

其中“b & 1”指取b的二进制数的最末位,如11的二进制数为1011,第一次循环,取的是最右边的“1” ,以此类推。

而“b >>= 1”等效于b = b >> 1,即右移1位,删去最低位。

以a11为例:

b的二进制数为1011,二进制从右向左算,但乘出来的顺序是 a20 *a21 *a23,是从左向右的。我们不断的让base *= base目的是累乘,以便随时对ans做出贡献。

其中要理解base *=base这一步:因为 base *base==base2,下一步再乘,就是base2 *base2==base4,然后同理 base4 *base4=base8,由此可以做到base–>base2–>base4–>base8–>base16–>base32…指数正是 2i ,再看上面的例子,a11= a1 *a2 *a8,这三项就可以完美解决了,快速幂就是这样。

注意:由于指数函数是爆炸增长的函数,所以很有可能会爆掉int的范围,可根据题意选择 long long。

知识点二:欧拉函数

浅谈欧拉函数

//求解欧拉函数
#typedef __int64 ll
ll ol(ll x)
{
	ll i,res=x;
	for(i=2;i*i<=x;i++)
	{
		if(x%i==0)
		{
			res=res-res/i;
			while(x%i==0)
				x/=i;
		}
	}
	if(x>1)
		res=res-res/x;
	return res;
}

知识点三:降幂公式

img

有了以上的知识储备,这题就有机会AC啦。

#include<iostream>
typedef __int64 ll;
const int max = 1e6 + 10;
char B[max];
ll A, C;
//快速幂
ll qsm(ll base, ll n) {
	ll ans = 1;
	while (n != 0) {
		if (n & 1 != 0) {
			ans = ans * base%C;
		}
		base = base * base%C;
		n >>= 1;
	}
	return ans;
}
//欧拉函数
ll ol(ll x) {
	ll i, ans = x;
	for (i = 2; i * i <= x; i++) {
		if (x%i == 0) {
			ans = ans - ans / i;
			while (x%i == 0) {
				x /= i;
			}
		}
	}
	if (x > 1) {
		ans = ans - ans / x;
	}
	return ans;
}
int main() {
	ll i, b, ans, tmp;
	while (scanf("%I64d%s%I64d", &A, B, &C) != EOF)
	{
		ans = 0; b = 0; tmp = ol(C);
		ll len = strlen(B);
		//字符按位转为整数并取模
		for (i = 0; i < len; i++)
			b = (b * 10 + B[i] - '0') % tmp;
		b += tmp;
		ans = qsm(A, b);
		printf("%I64d\n", ans);
	}
}

猜你喜欢

转载自blog.csdn.net/qq_26154135/article/details/89209705