2 条题解

  • 0
    @ 2026-6-2 16:57:19
    import sys
    from math import gcd
    n = int(input())
    a = map(int, sys.stdin.readline().strip().split())
    r = 0
    i = 0
    for ai in a:
        i+=1
        r+=n//(ai//gcd(ai,i))
    print(r)
    
    • 0
      @ 2025-7-6 19:22:14

      一、题意抽象

      • 给定长度为 nn 的正整数序列 {ai}i=1n\{a_i\}_{i=1}^n,且题目对每个公差 d=1,2,,nd=1,2,\dots,n 构造一个等差数列

        bi=id,i=1,2,,n. b_i = i\cdot d,\quad i=1,2,\dots,n.
      • 定义

        Sd=i=1n[aibi], S_d = \sum_{i=1}^n [\,a_i \mid b_i\,],

        其中 [][\,\cdot\,] 是指示函数,“1” 表示条件成立,“0” 表示不成立。也就是说,SdS_d 就是数有多少个下标 ii 使得 aia_i 能整除 bi=idb_i=i\cdot d

      • 要求最终答案

        d=1nSd. \sum_{d=1}^n S_d.

      朴素做法:对每个 dd 枚举所有 ii,判断 idmodai=ˉ0i\cdot d \bmod a_i\==0。最坏是 O(n2)O(n^2),当 nn 达到 10510^5 时不可行。


      二、数学化简

      二、观察与数学化简

      判断条件

      $$a_i \mid (i\cdot d) \;\Longleftrightarrow\; i\cdot d \equiv 0 \pmod{a_i} \;\Longleftrightarrow\; d \equiv 0 \pmod{\frac{a_i}{\gcd(a_i,i)}}.$$

      $$g_i = \gcd(a_i,\,i), \quad A_i' = \frac{a_i}{g_i}.$$

      则上式等价于

      Aid.A_i' \mid d.

      也就是说,对于固定的 ii,只有当 ddAiA_i' 的倍数时,[aiid][\,a_i \mid i\cdot d\,] 才为 1。

      因此

      Sd  =  i=1n[Aid],S_d \;=\;\sum_{i=1}^n \bigl[\,A_i'\mid d\,\bigr],

      我们要求

      $$\sum_{d=1}^n S_d =\sum_{d=1}^n \sum_{i=1}^n \bigl[\,A_i'\mid d\,\bigr] =\sum_{i=1}^n \sum_{d=1}^n \bigl[\,A_i'\mid d\,\bigr].$$

      对于固定的 ii,在 1dn1\le d\le n 中满足 AidA_i'\mid d 的一共有 $\displaystyle \left\lfloor \tfrac{n}{A_i'}\right\rfloor$ 个。

      于是

      $$\sum_{d=1}^n S_d =\sum_{i=1}^n \Bigl\lfloor \frac{n}{A_i'}\Bigr\rfloor =\sum_{i=1}^n \Bigl\lfloor \frac{n}{\,a_i/g_i\,}\Bigr\rfloor.$$

      三、从思路到代码

      1. 读取输入nn,数组 a[1n]a[1\ldots n]

      2. 遍历每个下标 ii

        • 计算 g=gcd(i,ai)g = \gcd(i,\,a_i)
        • A=ai/gA' = a_i / g
        • 累加答案 += n/A\lfloor n / A' \rfloor
      3. 输出累加结果

      此算法中每步 gcd\gcd 和一次除法、一次整除计数,都是 O(logn)O(\log n) 级别,整体 O(nlogn)O(n\log n),可轻松处理 n=105n=10^5


      四、代码

      #include <bits/stdc++.h>
      using namespace std;
      using ll = long long;
      
      int main() {
          ios::sync_with_stdio(false);
          cin.tie(nullptr);
      
          ll n;
          cin >> n;
      
          ll ans = 0;  // 最终答案累加器
      
          // 逐个读取 a_i,并即时累加对答案的贡献
          for (ll i = 1; i <= n; i++) {
              ll ai;
              cin >> ai;
      
              // 1. 计算 g = gcd(i, ai)
              ll g = std::gcd(i, ai);
      
              // 2. 化简后得到 A' = ai / g
              //    只有当 d 是 A' 的倍数时,(i, d) 配对才算 valid
              ll Ap = ai / g;
      
              // 3. 在 d = 1..n 范围内,A' 的倍数共有 floor(n/Ap) 个
              ans += n / Ap;
          }
      
          // 输出最终累加值
          cout << ans << "\n";
          return 0;
      }
      
      • 1

      信息

      ID
      176
      时间
      1000ms
      内存
      256MiB
      难度
      入门
      标签
      递交数
      110
      已通过
      39
      上传者