Loading

abc 293 E 题解

abc 293 E

题目传送门(洛谷)

题目传送门(AtCoder)

题意

给定 \(A, X, M\),请你求出 \(\sum \limits _{i = 0} ^ {X - 1} A ^ i \mod m\)

\(1 \le X \le 10 ^ {12}, 1 \le A, M \le 10 ^ 9\)

思路

首先,这题有一个很明显的暴力:枚举所有的 \(i\),将所有 \(A ^ i\) 累加起来。

但是这样的话,时间复杂度为 \(O(X)\),妥妥的超时。

所以我们可以考虑一种递归分治的做法。

\(S(n) = A ^ 1 + A ^ 2 + \dots A ^ n\)

  • \(n\) 为偶数:

\(S(n) = S(n / 2) + A ^ {n / 2 + 1} + \dots A ^ n\)

$ = S(n / 2) + (A ^ 1 \times A ^ {n / 2}) + \dots + (A ^ {n / 2} \times A ^ {n / 2})$

$ = S(n / 2) + (A ^ 1 + A ^ 2 + \dots A ^ {n / 2}) \times A ^ {n / 2}$

$ = S(n / 2) + S(n / 2) \times A ^ {n / 2}$

实际上,\(n\) 为奇数的情况与偶数并没有什么不同,只是要在求和的时候多加上一个 \(A ^ n\) 而已。

  • \(n\) 为奇数:

\(S(n) = S(\lfloor n / 2 \rfloor) + A ^ {\lfloor n / 2 \rfloor + 1} + \dots A ^ n\)

$ = S(\lfloor n / 2 \rfloor) + (A ^ 1 \times A ^ {\lfloor n / 2 \rfloor}) + \dots + (A ^ {\lfloor n / 2 \rfloor} \times A ^ {\lfloor n / 2 \rfloor}) + A ^ n$

$ = S(\lfloor n / 2 \rfloor) + (A ^ 1 + A ^ 2 + \dots A ^ {\lfloor n / 2 \rfloor}) \times A ^ {\lfloor n / 2 \rfloor} + A ^ n$

$ = S(\lfloor n / 2 \rfloor) + S(\lfloor n / 2 \rfloor) \times A ^ {\lfloor n / 2 \rfloor} + A ^ n$

由于这里我定义的是 \(S(n) = A ^ 1 + \dots + A ^ n\),所以要将 \(A ^ 0\) 再最后单独计算一下。

代码

#include <bits/stdc++.h>

using namespace std;

int a, m;
long long w;

struct Node {
  long long x, y; 
};

Node P(long long t) {
  if (t <= 1) {
    /*
    这里有一个问题,之所以要写成 t <= 1,是因为 w 有可能为 1
    若 w = 1,那么传进来的 t 就会是 0,如果只判断 t == 1,会无限递归,RE
    */
    return {t * a % m, t * a % m};
  }
  Node x = P(t / 2);
  long long p = x.x * x.x % m;
  // x.x 为 A ^ (t / 2),x.y 为 A ^ 1 + ... + A ^ (t / 2)
  x.y = (x.y + x.y * x.x % m) % m;  // 求和
  if (t % 2 == 1) {  // 若 n 为奇数 
    p = p * a % m, x.y = (x.y + p) % m;
  }
  x.x = p;
  return x;
}

int main() {
  cin >> a >> w >> m;
  // P(w - 1) 求 A ^ 1 + ... + A ^ (w - 1)
  cout << (P(w - 1).y + 1) % m;
  return 0;
}
posted @ 2023-03-14 11:26  chengning0909  阅读(20)  评论(0编辑  收藏  举报