我遇到了这个问题:
给出a,b和c三 自然数(例如1 <= a,b,c <= 10 ^ 9),你应该找到数字a ^ b ^ c的最后一位数。“
我首先想到的是用于提高功率n的O(log n)算法。
var xmlPaths = new[]
{
HttpContext.Current.Server.MapPath("~/bin/Path.To.FirstNamespace.XML"),
HttpContext.Current.Server.MapPath("~/bin/Path.To.OtherNamespace.XML")
};
var documentationProvider = new XmlDocumentationProvider(xmlPaths);
config.SetDocumentationProvider(documentationProvider);
显然,一些基本的数学可能会有所帮助,比如“最后一位数字”:
int acc=1; //accumulator
while(n>0) {
if(n%2==1)
acc*=a;
a=a*a;
n/=2;
}
其中n%4是除法的剩余部分n / 4
简而言之,我试图将这些结合起来,但我无法顺利进行。
有些帮助真的会被贬低。
答案 0 :(得分:6)
问题是b^c
可能非常大。因此,您希望在使用标准模幂运算之前减少它。
您可以注意到a^(b^c) MOD 10
最多可以包含10个不同的值。
由于鸽笼原则,对于某些p
,会有r
个a^r MOD 10 = a^(p+r) MOD 10
p <= 10
r <= 10
:
q
这意味着任何a^r MOD 10 = a^r*a^p MOD 10
= (a^r*a^p)*a^p MOD 10
= ...
= a^(r+q*p) MOD 10
:
n = s+r+q*p
对于任何s < p
,a^n MOD 10 = a^s*a^(r+q*p) MOD 10
= a^s*a^r MOD 10
= a^((n-r) MOD p)*a^r MOD 10
都有:
n= (b^c)
您只需替换上一个等式中的(b^c-r) MOD p
即可。
您只需计算p <= 10
a^((b^c-r) MOD p)*a^r MOD 10
哪里可以轻松完成,然后计算""
。
答案 1 :(得分:4)
就像我在评论中提到的那样,这与智能算法没什么关系。使用一些基本数论可以完全减少问题。这将产生O(1)算法。
中国剩余定理说,如果我们知道一些数x模2和模5,我们知道它模10。所以找到一个^ b ^ c模10可以简化为找到一个^ b ^ c模2和a ^ b ^ c modulo 5.费马的小定理说对于任何素数p,如果p不除a,则a ^(p-1)= 1(mod p),所以a ^ n = a ^ (n mod(p-1))(mod p)。如果p确实除了a,则显然对于任何n> 1,^ n = 0(mod p)。注意,对于任何n> 0,x ^ n = x(mod 2),所以a ^ b ^ c = a(mod 2)。
剩下的就是找到一个^ b ^ c mod 5,它减少到找到b ^ c mod 4.不幸的是,我们既不能使用中文余数定理,也不能使用Fermat的小定理。但是,mod 4只有4种可能性,所以我们可以单独检查它们。如果我们从b = 0(mod 4)或b = 1(mod 4)开始,那么当然b ^ c = b(mod 4)。如果我们有b = 2(mod 4)那么很容易看出如果c = 1则b ^ c = 2(mod 4),并且如果c> 1,则b ^ c = 0(mod 4)。 1.如果b = 3(mod 4),那么如果c是偶数则b ^ c = 3,如果c是奇数则b ^ c = 1。这给了我们任何b和c的b ^ c(mod 4),然后给我们一个^ b ^ c(mod 5),所有这些都是在恒定的时间内。
最后用^ b ^ c = a(mod 2)我们可以使用中国余数定理来找到^ b ^ c(mod 10)。这需要(x(mod 2),y(mod 5))和z(mod 10)之间的映射。中国剩余定理只告诉我们这种映射是双射的,它并没有告诉我们如何找到它。但是,只有10个选项,因此可以在一张纸上或使用一个小程序轻松完成。一旦我们找到这个映射,我们只需将它存储在一个数组中,我们就可以在O(1)中完成整个计算。
顺便说一下,这将是我在python中实现的算法:
# this table only needs to be calculated once
# can also be hard-coded
mod2mod5_to_mod10 = [[0 for i in range(5)] for j in range(2)]
for i in range(10):
mod2mod5_to_mod10[i % 2][i % 5] = i
[a,b,c] = [int(input()) for i in range(3)]
if a % 5 == 0:
abcmod5 = 0
else:
bmod4 = b % 4
if bmod4 == 0 or bmod4 == 1:
bcmod4 = bmod4
elif bmod4 == 2:
if c == 1:
bcmod4 = 2
else:
bcmod4 = 0
else:
if c % 2 == 0:
bcmod4 = 1
else:
bcmod4 = 3
abcmod5 = ((a % 5)**bcmod4) % 5
abcmod2 = a % 2
abcmod10 = mod2mod5_to_mod10[abcmod2][abcmod5]
print(abcmod10)