Files
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

154 lines
4.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

##[$AcWing$ $1289$. 序列的第$K$个数](https://www.acwing.com/problem/content/1291/)
### 一、题目描述
$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$
**输入样例**
```cpp {.line-numbers}
2
1 2 3 5
1 2 4 5
```
**输出样例**
```cpp {.line-numbers}
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$进制加起来,用于数据很大的情况
### 五、实现代码
```cpp {.line-numbers}
#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; // 这个需要快速幂
}
}
```
### 六、龟速乘版本
```cpp {.line-numbers}
#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; // 等比数列用快速幂算末项
}
}
```