这是我用来计算(n^p)%mod
的代码。不幸的是,当我从mod
方法调用它时,mod = 10000000000ULL
(在我的情况下为main()
)的值很大。任何的想法;为什么呢?
ull powMod(ull n, ull p, ull mod) {
ull ans = 1;
n = n%mod;
while(p) {
if(p%2 == 1) {
ans = (ans*n)%mod;
}
n = (n*n)%mod;
p /= 2;
}
return ans;
}
此处,ull
是unsigned long long
的typedef。
答案 0 :(得分:3)
是的,你可以用C ++来做。正如其他人指出你不能直接那样做。使用一点数论可以将问题分解为两个可管理的子问题。
首先考虑10^10 = 2^10 * 5^10
。这两个因素都是互质的,因此您可以使用{modoro 10^10
和modulo 2^10
来为Chinese remainder theorem找到幂模5^10
。
请注意,在以下代码中,使用Extended Euclidean Algorithm找到了 magic 值u2
和u5
。您不需要自己编写此算法,因为这些值是常量。我使用maxima及其gcdex函数来计算它们。
以下是修改后的版本:
typedef unsigned long long ull;
ull const M = 10000000000ull;
ull pow_mod10_10(ull n, ull p) {
ull const m2 = 1024; // 2^10
ull const m5 = 9765625; // 5^10
ull const M2 = 9765625; // 5^10 = M / m2
ull const M5 = 1024; // 2^10 = M / m5
ull const u2 = 841; // u2*M2 = 1 mod m2
ull const u5 = 1745224; // u5*M5 = 1 mod m5
ull b2 = 1;
ull b5 = 1;
ull n2 = n % m2;
ull n5 = n % m5;
while(p) {
if(p%2 == 1) {
b2 = (b2*n2)%m2;
b5 = (b5*n5)%m5;
}
n2 = (n2*n2)%m2;
n5 = (n5*n5)%m5;
p /= 2;
}
ull np = (((b2*u2)%M)*M2)%M;
np += (((b5*u5)%M)*M5)%M;
np %= M;
return np;
}
答案 1 :(得分:1)
似乎你无法避免它。
如果mod
为10000000000ULL
,则在您的计划的(a*b)%c
中,a
和b
都小于mod,因此我们将其视为{{1} },9999999999ULL
将为a*b
,但99999999980000000001
只能表达unsigned long long
,因此您的方法会溢出。
答案 2 :(得分:0)
这里可能出现的问题之一似乎是当你(a*b)%c
时,a*b
部分本身可能会溢出,从而导致错误答案。解决这个问题的一种方法是使用
(a*b)%c
相当于
(a%c * b%c)%c
这也可以防止中间乘法中的溢出。
答案 3 :(得分:0)
您的代码行
n = (n*n)%mod;
重复执行。 只要n小于mod,这可能会导致在某个时间点评估(mod-1)*(mod-1)。
输入n可能不是那么大,但是上面提到的代码行在循环中增加了n。