牛客网-求root(N, k)【快速幂+模运算规律总结】

在这里插入图片描述

模运算规律总结

运算规则

模运算与基本四则运算有些相似,但是除法例外。其规则如下:


(a + b) % p = (a % p + b % p) % p (1)

(a – b) % p = (a % p – b % p) % p (2)

(a * b) % p = (a % p * b % p) % p (3)

(a^b) % p = ((a % p)^b) % p (4)


结合律:

((a+b) % p + c) % p = (a + (b+c) % p) % p (5)

((ab) % p * c)% p = (a * (bc) % p) % p (6)


交换律:

(a + b) % p = (b+a) % p (7)

(a * b) % p = (b * a) % p (8)


分配律:

((a +b)% p * c) % p = ((a * c) % p + (b * c) % p) % p (9)


重要定理:

若a≡b (% p),则对于任意的c,都有(a + c) ≡ (b + c) (%p);(10)

若a≡b (% p),则对于任意的c,都有(a * c) ≡ (b * c) (%p);(11)

若a≡b (% p),c≡d (% p),则 (a + c) ≡ (b + d) (%p),(a – c) ≡ (b – d) (%p),

快速幂与矩阵快速幂

辗转相除法,求素数预算,快速幂预算
矩阵快速幂

题解

这道题首先需要看到一个数理上的规律,首先对于k进制的数,我们可以把他写成如下形式
N = a 0 + a 1 k + a 2 k 2 + . . . + a n k n N=a_0+a_1*k+a_2*k^2+...+a_n*k^n
N = a 0 + a 1 + . . . + a n N'=a_0+a_1+...+a_n
两式相减我们可以得到
N N = a 1 ( k 1 ) + a 2 ( k 2 1 ) + . . . + a n ( k n 1 ) N-N'=a_1(k-1)+a_2(k^2-1)+...+a_n(k^n-1)
可以看到每一个项都有一个 ( k 1 ) (k-1) 的项,那么左边对(k-1)取余显然结果为0,即 ( N N ) (N-N')%(k-1)=0 。同理,只要我们的 N N' 项不小于 k k ,这个过程就会一直继续下去,我们记这个过程求出的所有 N N N , N , N , N r N,N',N'',N^r (我们总会碰到一项 N r N^r ,使得 N r < k 1 N^r<k-1 ),那么我们有:

( N N ) % ( k 1 ) = 0 (N-N')\%(k-1)=0
( N N ) % ( k 1 ) = 0 (N'-N'')\%(k-1)=0
( N r 1 N r ) % ( k 1 ) = 0 (N^{r-1}-N^r)\%(k-1)=0
根据上门上述的模运算规律,我们将左侧所有项相加
( N N r ) % ( k 1 ) = 0 (N-N^r)\%(k-1)=0
N % ( k 1 ) = N r % ( k 1 ) N\%(k-1)=N^r\%(k-1)
因为 N r N^r 已经比 k 1 k-1 小了,所以得到
N % ( k 1 ) = N r \color{blue}N\%(k-1)=N^r
那么只要我们得到N的值,就可以直接求出结果,现在问题变成了 x y x^y ,这么大的数据范围显然不可能pow水过,那么大数乘法+快速幂?太麻烦了求模运算不好施展。所以我们使用求模运算的性质,在求出N的过程中不断取模即可。

#include<iostream>
#include<string>
#include<string.h>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
using namespace std;

#define ll unsigned long long
#define MAX 250
#define inf 10000000

ll root(ll x, ll y, ll k) {
	ll base = x, ans = 1;
	while (y > 0) {
		if (y & 1)ans = (ans % (k - 1)* base % (k - 1)) % (k - 1);
		base = ((base % (k - 1))*(base % (k - 1))) % (k - 1); y >>= 1;
	}
	if (ans == 0)ans = k - 1;
	return ans;
}

int main() {
	ll x, y, k;
	while (cin >> x >> y >> k) {
		cout << root(x, y, k) << endl;
	}
}
发布了269 篇原创文章 · 获赞 16 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/csyifanZhang/article/details/105623224