第18节 华华教月月做数学(快速幂+__int128/快速幂)

第18节 华华教月月做数学
求(A^B)mod P
输入描述:
第一行一个正整数T表示测试数据组数。
接下来T行,每行三个正整数A、B、P,含义如上文。

示例1
输入
2
2 5 10
57284938291657 827493857294857 384729583748273
输出
2
18924650048745

备注:
A B P<1e18
t<1e3


快速幂+__int128


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
__int128 qpow(__int128 a,__int128 b,__int128 mod)//快速幂非递归模板
{
    __int128 sum=1;
    while(b)
    {
        if(b&1)
        {
            sum=(sum%mod*a%mod)%mod;
        }
        a=(a%mod*a%mod)%mod;
        b>>=1;
    }
    return sum%mod;
}
int main()
{
    int t;
    cin>>t;
    ll a,b,mod;
    while(t--)
    {
       cin>>a>>b>>mod;
       ll ans=qpow(a,b,mod);
       cout<<ans<<endl;
    }
    return 0;
}

__int128

思路:首先欧拉降幂是不行的,A^B %P,然而P的范围是[1,10^18],依然会爆long long,那怎么办呢?用到了一种很神奇的东西,这玩意就是__int128,故名思议,就是有128位的整数,其表示的范围大概在10^36以内。(具体多少我没算)反正这道题是够用了,但是这玩意你的编译器可能不认识,评测机是认识的。(比如我的CB编译就通不过)但是不妨碍我们使用,这东西不能用cin和cout读入和输出,因此要我们自己实现一个读入和输入的方法。快速幂就不多说了。


#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
typedef long long ll;
using namespace std;
 
__int128 a,b,c;
 
inline __int128 read()//读入
{
	__int128 x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-')
			f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=x*10+ch-48;
		ch=getchar();
	}
	return x*f;
}
 
void print(__int128 x)//输出
{
    if(x > 9)
		print(x/10);//递归调用
    putchar(x%10+48);
}
 
void cal()//快速幂
{
	__int128 t1=a,t2=1;
	while(b>0)
	{
		if(b&1)
			t2=t2*t1%c;
		t1=t1*t1%c;
		b>>=1;
	}
	print(t2);
}
 
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		a=read(),b=read(),c=read();
		cal();
		putchar('\n');
	}
	return 0;
}

快速幂+快速乘
快速乘:
我们知道,在计算机中做加法运算会比乘法快得多(参考模电中的加法器),做乘法运算往往会溢出,即使用 long long 类型也拯救不了。因此需要寻找一种能高效完成乘法运算且不会溢出的算法,这就是快速乘算法。

#include<bits/stdc++.h>
using namespace std;
 
typedef long long ll;
const double eps=1.0e-5;
const int maxn=200000+10;
const ll mod=1e9+7;
 
ll quick_mul(ll a,ll b,ll c)
{
	ll ans=0;
	while(b){
		if(b&1) ans=(ans+a)%c;
		a=(a+a)%c;
		b>>=1;
	}  
	return ans;
}
 
ll quick_pow(ll a,ll b,ll c)
{
	ll ans=1;
	while(b){
		if(b&1) ans=quick_mul(ans,a,c);
		a=quick_mul(a,a,c);
		b>>=1;
		}
	return ans;
}
 
int t;
ll a,b,c;
 
int main()
{
	scanf("%d",&t);
	while(t--){
		scanf("%lld %lld %lld",&a,&b,&c);
		printf("%lld\n",quick_pow(a,b,c));
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值