【其他技巧】光速幂

\(k\) 进制倍增

\(a, p\) 一定,求

\[a^x \bmod p \]

1. 朴素

基本的欧拉降幂就不说了,可以将 \(x\) 缩小到 \(\varphi(p)\le p\) 的范围内 .

考虑分块预处理,令 \(r = \lfloor\sqrt p\rfloor\),则我们可以把 \(a^x\) 分成几个整块的 \(a^r\) 和一个散的

预处理 \(a^r, (a^r)^2, (a^r)^3, \cdots, , (a^r)^r\)\(a, a^2\cdots, a^r\),然后我们就可以求 \(a^x\)

\[a_x = a^{rp + q} = (a^r)^p\cdot a^q \]

这里 \(rp+q\) 类似一个带余除法,\(0\le q < r\) .

这样空间复杂度 \(O(\sqrt p)\),时间复杂度 \(O(\sqrt p) - O(1)\)

这玩意还可以用类似方法搞搞扩域光速幂,矩阵光速幂啥的 .

Code:

template<int MOD>
struct FastPow
{
private:
	ll p1[66666],p2[66666];
	static ll qpow(ll a,ll n)
	{
		ll ans=1;
		while (n)
		{
			if (n&1) ans=ans*a%MOD;
			a=a*a%MOD; n>>=1;
		} return ans%MOD;
	}
public:
	explicit FastPow(ll a)
	{
		ll t1=a,t2=qpow(t1,65536); p1[0]=p2[0]=1;
		for (int i=1;i<65536;i++) p1[i]=p1[i-1]*t1%MOD;
		for (int i=1;i<65536;i++) p2[i]=p2[i-1]*t2%MOD;
	}
	ll operator()(unsigned n){return p2[n>>16]%MOD*p1[n&65535]%MOD;}
};

例题:块速递推

2. 不朴素

我们这个 \(r\) 也不一定取 \(\sqrt p\) .

类似快速幂,我们拆

\[a^x = a^{x\bmod k}\cdot (a^k)^{\lfloor x/k\rfloor} \]

左边预处理,右边做递归 .

这一般被叫做 \(k\) 进制倍增,当 \(k=2\) 时等价于快速幂 .

这个可以用来调节预处理复杂度和询问复杂度,例如 \(r\)\(p^{1/3}\) 时 .

空间复杂度 \(O(k\log_k p)\) 时间复杂度 \(O(k\log_k p) - O(\log_k p)\)(有错望指正).

例题:能量采集

posted @ 2022-08-18 19:12  STA_Morlin  阅读(89)  评论(0)    收藏  举报