1. 问题分析

本题的核心要求是处理两个具有依赖关系的序列

  • 序列 A:基于线性同余的递推关系, 仅依赖于 。这是一个单调生成的序列。
  • 序列 B 定义为 的所有约数 对应的 之和。这是一个经典的数论变换问题(Dirichlet Convolution 的变种,即 ,其中 是全 1 序列)。
  • 目标:计算整个序列 的异或和。

不可行的思路:

  1. naive 算法的不可行性:最直观的做法是,先生成 ,然后对每个 枚举其约数计算 。对于每个数 ,枚举约数的时间复杂度为 。总复杂度为 。当 时,计算量达到 级别,显然超时。
  2. 的非积性:序列 的生成公式 本质上是一个二次函数(求和公式导致)。 并不具备积性函数(Multiplicative Function)的性质(即 ),这意味着我们无法直接使用欧拉筛(Linear Sieve)在 时间内通过积性推导

2. 核心算法:调和级数筛法 (贡献法)

为了优化计算 的过程,我们需要转换视角通过贡献法来改变计算顺序。

  • 原始视角:对于每个 ,去寻找它的因子 。即 "谁是我的因子?"
  • 优化视角:对于每个 ,去寻找它的倍数 。即 "我是谁的因子?"

根据定义 ,这意味着 会被累加到 中。 我们可以遍历 ,将 的值累加到所有 的倍数位置的 数组中。

为什么选择此范式: 这种基于倍数的遍历方式(类似埃氏筛法 Eratosthenes Sieve 的逻辑),其复杂度受调和级数控制,远优于 ,且无需 具备积性函数特征,是解决此类通用约数和问题的最优解。

3. 算法复杂度分析

  • 时间复杂度: 序列 的生成为 。 序列 的计算涉及两层循环:外层枚举 从 1 到 ,内层枚举倍数 。 总操作次数为: 因此,时间复杂度为

    对比:在 下, 次操作,完全符合 1 秒的时限要求。

  • 空间复杂度: 我们需要存储序列 来累加结果。空间复杂度为 优化点:序列 不需要完整保存,可以在遍历 时动态生成 ,从而将辅助空间减少一半。

4. 代码实现

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int N, A1, M;
    cin >> N >> A1 >> M;

    vector<int> B(N + 1, 0);
    int curA;
    int lastA;

    for (int i = 1; i <= N; i++) {
        curA = (i == 1) ? A1 : (lastA + 7 * i) % M;
        lastA = curA;
        for (int j = i; j <= N; j += i) {
            B[j] += curA;
        }
    }

    int ans = 0;
    for (int i = 1; i <= N; i++) {
        ans ^= B[i];
    }
    cout << ans << endl;
}