快速幂 Quick pow

本文使用非递归方法,即二进制
对于 \(a^p\) 来说,如果把 p 写成二进制,那么他就可以写成诺干的的二次幂的和。例如 13 的二进制 1101,在 3 号位,2号位以及0 号位都是 1,那么 \(13=2^3+2^2+2^0=8+4+1\)。所以 \(a^{13} =a^8*a^4*a^1\)
同理,我们可以把 \(a^p\) 表示为 \(a^{2^k} ...a^2,a^1\) 中若干的积。若二进制对应的 \(i\) 号位为 1 ,即代表 \(a^{2^i}\) 被选中,于是得到了计算思路。

  • 初始一个 \(res=1\) 用来存放结果。
  • 判断 \(p\) 的二进制末尾是否为1,是的话就乘上 \(a\) 的值。
  • 平方 \(a\) 并把 \(p\) 右移一位。

其中,判断二进制末尾是否为1可以理解为判断是否为奇数,右移一位可以理解为p/2。
最后,放上一道并不是那么模板的模板题。(前置芝士:费马小定理)
洛谷P2613

\(Code\)

#include<bits/stdc++.h>
#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#define gc getchar
#include<algorithm>
#define reg register
#define ll long long
#define int long long
using namespace std;
const int N=1e5+5;
const int mod=19260817;
const int INF = 0x3f3f3f3f;
inline void print(int x) {if (x < 0) putchar('-'), x = -x; if(x > 9) print(x / 10); putchar(x % 10 + '0');}
inline int read() { int res = 0, f = 0; char ch = gc();for (; !isdigit(ch); ch = gc()) f |= (ch == '-'); for (; isdigit(ch); ch = gc()) res = (((res << 1) + (res << 3) + (ch ^ '0'))%mod); return f ? (-res)%mod : (res)%mod;}

int a,b;

inline int quick_pow(int x,int p)
{
	int res=1;
	while(p)
	{
		if(p & 1) res=((res%mod)*(x%mod))%mod;
		x=((x%mod)*(x%mod))%mod;
		p >>= 1;
	}
	return res;
}

signed main()
{
	a=read(),b=read();
	if(!b)
	{
		printf("Angry!");
		return 0;
	}
	b=quick_pow(b,mod-2);
	printf("%lld",((a%mod)*(b%mod))%mod);
	return 0;
 } 
posted @ 2022-07-20 09:28  Always_maxx  阅读(74)  评论(0编辑  收藏  举报