【題解】A23329.等差數列計數

Macw發表於2024-06-11

題目連結:等差數列計數

題目描述

首先根據題目要求,給定一個等差數列的首項 \(t_1\) 和這個等差數列的末項 \(t_n\),問符合這個形式的等差數列的數量。

例如,對於第一個 \(\mathtt{Testcase}\),當 \(t_1\)\(1\)\(t_n\)\(9\) 時,可行的等差數列方案數有四個,分別為以下所示:

  1. \(S = \{1, 2, 3, 4, 5, 6, 7, 8, 9\}\)
  2. \(S = \{1, 3, 5, 7, 9\}\)
  3. \(S = \{1, 5, 9\}\)
  4. \(S = \{1, 9\}\)

思路分析

我們知道,等差數列的公差數量就是這個等差數列的可行方案數,即有多少種不同的公差方案,就可以構造出多少種不同的等差數列。因此透過分析題意,我們可以將問題更細緻地轉換為 已知等差數列的首項和尾項,求出這個等差數列公差的可行方案數。所以對於本題而言,我們只需要求出有多少個公差就可以了。

顯然本題的就引刃而解了,我們只需要求出這個等差數列首項和末項的差的絕對值,即 \(diff = \lvert t_n - t_1 \rvert\)。然後我們只需要求出 \(diff\) 的因數個數即可。\(diff\) 的因數就是可行的因數方案(詳細證明過程見下文)。

例如,當 \(t_1\)\(1\)\(t_n\)\(9\) 時,\(diff = \lvert 9 - 1 \rvert = 8\)\(8\) 的因數有四個,分別是 \(\{1, 2, 4, 8\}\),因此當這個等差數列首項為 \(1\),末項為 \(9\) 時,可行的等差數列方案應為四個。

結論證明

透過等差數列公式,我們可以將等差數列的首項和末項透過公式聯立起來,得到 \(t_n = t_1 + (n-1)\times d\),其中 \(n\) 表示等差數列的項數,\(d\) 表示等差數列的公差。

由於我們想要求解所有的因數個數,因此我們將透過移項的操作將 \(d\) 放到等式左邊,將其餘的量都放到等式右邊。得到:

\[\begin{equation} \begin{split} t_n - t_1 &= (n-1) \times d \\ d &= \frac{t_n - t_1}{n-1} \end{split} \end{equation} \]

由於等差數列的性質,\(n - 1\) 必須為非負整數(等差數列的長度不能 \(0\))。或者根據等差數列的另一個性質,如果首項和末項的差為負數,那麼公差也必須為負數,反之亦然。因此也可以推匯出 \(n - 1\) 必須是非負整數。

為了方便起見,我們將 \(n-1\) 看作為一個整體,另 \(\Delta t = n - 1\)。將該整體代入方程後即可得到 \(d = \frac{t_n - t_1}{\Delta t}\)。為了使 \(d\) 是一個整數,因此 \(t_n - t_1\) 必須是 \(\Delta t\) 的倍數。因此我們只需要透過列舉上述方程,計算 \(t_n - t_1\) 所有的因數數量就可以得到本問題的解。

AC 程式碼

以下是本題的 AC 程式碼。需要注意的是,由於本題的資料量比較大,因此在判斷因數的過程中需要最佳化演算法(與判斷質數類似),這樣子演算法就可以在 \(O(\sqrt{n})\) 的時間內完成列舉,不至於超時:

#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;

int t, a, b;

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    cin >> t;
    while(t--){
        cin >> a >> b;
        int change = abs(b - a), cnt = 0;
        for (int i=1; i*i<=change; i++){
            if (change % i == 0){
                if (i*i != change) cnt += 2;
                else cnt += 1;
            }
        }
        cout << cnt << endl;
    }
    return 0;
}

相關文章