AcWing 1289. 序列的第k个数

\(AcWing\) \(1289\). 序列的第\(K\)个数

一、题目描述

\(BSNY\) 在学等差数列和等比数列,当已知前三项时,就可以知道是等差数列还是等比数列。

现在给你 整数 序列的前三项,这个序列要么是等差序列,要么是等比序列,你能求出第 \(k\) 项的值吗?

如果第 \(k\) 项的值太大,对其取模 \(200907\)

输入格式
第一行一个整数 \(T\),表示有 \(T\) 组测试数据;

对于每组测试数据,输入前三项 \(a,b,c\),然后输入 \(k\)

输出格式
对于每组数据,输出第 \(k\) 项取模 \(200907\) 的值。

数据范围
\(1≤T≤100\)
\(1≤a≤b≤c≤10^9\)
\(1≤k≤10^9\)

输入样例

2
1 2 3 5
1 2 4 5

输出样例

5
16

二、\(Q\):一个数列能不能即是等差数列又是等比数列?

结论:一个数列如果是即是等差又是等比,那么它必然是一个全等数列

证明
设三个连续数字\(a\ b \ c\),
等差数列,所以\(a+c=2b\)
等比数列,所以\(\frac{b}{a}=\frac{c}{b}\),所以\(b^2=ac\)

\(a=2b-c\)代入②
\(b^2=(2b-c)*c\)
\(b^2=2bc-c^2\)
\(b^2-2bc+c^2=0\)
\((b-c)^2=0\)
\(b=c\)

由此可知,题目中给了数列的前三项,存在可能即是等差又是等比的情况,但此时就是一个全等数列,按哪个规则进行计算都是一样的结果,题目不缺少条件。

三、题意分析

  • 等差数列
    公差 \(d=b-a\)
    \(1\)项,\(a+0*d\)
    \(2\)项,\(a+1*d\)
    \(3\)项,\(a+2*d\)
    ...
    \(k\)项,应该是\(a+(k-1)d\),这个很好求,直接求然后注意取模就行了。

  • 等比数列
    公比\(p=\frac{b}{a}\)
    \(1\)项,\(a*p^0\)
    \(2\)项,\(a*p^1\)
    \(3\)项,\(a*p^2\)
    ...
    \(k\)项,\(a*p^{k-1}=a*(\frac{b}{a})^{k-1}\)

    这东西用 快速幂 就行了

四、理解与思考

数学的题,一般不会真的用代码去暴力计算,通常是推公式,证明。在完成公式的推导后,再用代码进行简单计算,比如\(2022\) \(CSP-J\)的第二题就是一道公式的推导题,小心下细节就行了。

  • 快速幂:把次数依次化为\(2\)进制,即可迭代
  • 龟速乘:把当前数变为\(2\)进制加起来,用于数据很大的情况

五、实现代码

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MOD = 200907;

// 快速幂
int qmi(int a, int b) {
    int res = 1;
    while (b) {
        if (b & 1) res = res * a % MOD;
        a = a * a % MOD;
        b >>= 1;
    }
    return res;
}

signed main() {
    int n;
    cin >> n;
    while (n--) {
        int a, b, c, k;
        cin >> a >> b >> c >> k;
        if (a + c == b * 2)                                // 等差
            cout << (a + (b - a) * (k - 1)) % MOD << endl; // 这个比较简单
        else                                               // 等比
            cout << a * qmi(b / a, k - 1) % MOD << endl;   // 这个需要快速幂
    }
}

六、龟速乘版本

#include <bits/stdc++.h>
using namespace std;
#define int long long

const int MOD = 200907;

// 龟速乘,快速加
int qadd(int a, int b) {
    int res = 0;
    while (b) {
        if (b & 1) res = (res + a) % MOD;
        b >>= 1;
        a = (a + a) % MOD;
    }
    return res;
}

// 快速幂
int qmi(int a, int b) {
    int res = 1;
    while (b) {
        if (b & 1) res = (res * a) % MOD;
        b >>= 1;
        a = a * a % MOD;
    }
    return res;
}

signed main() {
    int T;
    cin >> T;
    while (T--) {
        int a, b, c, k;
        cin >> a >> b >> c >> k;
        if (a + c == b + b)
            cout << (qadd(b - a, k - 1) + a) % MOD << endl; // 为等差即套公式,首项+公差*(项数-1)
        else
            cout << qmi(b / a, k - 1) * a % MOD << endl; // 等比数列用快速幂算末项
    }
}
posted @ 2022-05-18 13:49  糖豆爸爸  阅读(85)  评论(0编辑  收藏  举报
Live2D