有3个数字:T, N, M. 1 ≤ T, M ≤ 10^9, 1 ≤ N ≤ 10^18
。
问题中的问题是计算[Σ(T^i)]mod(m)
,其中i从0变化到n。显然,由于1秒的时间限制,O(N)或O(M)解决方案不起作用。我该怎么办?
答案 0 :(得分:1)
正如之前的答案中所指出的,您可以使用几何级数和的公式。然而,存在一个小问题 - 如果m不是素数,则计算(T^n - 1) / (T - 1)
不能直接完成 - 除法不是明确定义的操作。事实上,有一种解决方案甚至可以处理非主要模块,并且具有复杂性O(log(n) * log(n))
。该方法类似于二进制求幂。这是我用c ++编写的代码(注意我的解决方案在内部使用二进制取幂):
typedef long long ll;
ll binary_exponent(ll x, ll y, ll mod) {
ll res = 1;
ll p = x;
while (y) {
if (y % 2) {
res = (res * p) % mod;
}
p = (p * p) % mod;
y /= 2;
}
return res;
}
ll gp_sum(ll a, int n, ll mod) {
ll A = 1;
int num = 0;
ll res = 0;
ll degree = 1;
while (n) {
if (n & (1 << num)) {
n &= (~(1 << num));
res = (res + (A * binary_exponent(a, n, mod)) % mod) % mod;
}
A = (A + (A * binary_exponent(a, degree, mod)) % mod) % mod;
degree *= 2;
num++;
}
return res;
}
在此解决方案A
中连续存储值1
,1 + a
,1 + a + a^2 + a^3
,... 1 + a + a^2 + ... a ^ (2^n - 1)
。
就像二进制求幂一样,如果我想计算n
a
度的总和,我将n
分成两个幂的和(基本上使用二进制表示法) n
)。现在具有A
的上述值序列,我选择适当的长度(对应于1
的二进制表示的n
位的长度)并将该和乘以某个值a
将结果累加到res
。计算A
的值将花费O(log(n))
时间,对于每个值,我可能需要计算a
度,这将导致另一个O(log(n))
- 因此我们总体而言{ {1}}。
我们举一个例子 - 我们想要计算O(log(n) * log (n))
。在这种情况下,我们致电1 + a + a^2 .... + a ^ 10
。
在第一次迭代时,gp_sum(a, 11, mod)
不为零,因为11的第一位(n & (1 << 0)
)为1.因此,我将此位设置n关闭为1011(2)
,并在res中累积:10
= 0 + 1 * (a ^ (10))
。 A现在是a^10
。
下一个第二位也设置为10(a + 1
),因此现在n变为1010(2)
而8
变为res
= a^10 + (a + 1)*(a^8)
。 A现在是a^10 + a^9 + a^8
下一位为0,因此res保持不变,但A将变为1 + a + a^2 + a^3
。
在最后一次迭代中,该位为1,因此我们有:
1 + a + a^2 + ... a^7
= res = a^10 + a^9 + a^8 + a^0 *(1 + a + a^2 + ... +a^7)
。
答案 1 :(得分:0)
可以使用类似于二进制求幂的算法:
// Returns a pair <t^n mod m, sum of t^0..t^n mod m>,
// I assume that int is big enough to hold all values without overflowing.
pair<int, int> calc(int t, int n, int m)
if n == 0 // Base case. t^0 is always 1.
return (1 % m, 1 % m)
if n % 2 == 1
// We just compute the result for n - 1 and then add t^n.
(prevPow, prevSum) = calc(t, n - 1, m)
curPow = prevPow * t % m
curSum = (prevSum + curPow) % m
return (curPow, curSum)
// If n is even, we compute the sum for the first half.
(halfPow, halfSum) = calc(t, n / 2, m)
curPow = halfPow * halfPow % m // t^n = (t^(n/2))^2
curSum = (halfSum * halfPow + halfSum) % m
return (curPow, curSum)
时间复杂度为O(log n)
(分析与二进制求幂算法相同)。为什么它比几何级数的封闭式公式更好?后者涉及(t - 1)
除以。但不保证存在t - 1
mod m
的倒数。
答案 2 :(得分:-1)
你可以用这个:
a^1 + a^2 + ... + a^n = a(1-a^n) / (1-a)
所以,你只需要计算:
a * (1 - a^n) / (1 - a) mod M
你可以找到O(logN)方法来计算一个^ n mod M
答案 3 :(得分:-2)
它是一个几何级数,其总和等于: