This commit is contained in:
HuangHai
2025-08-30 18:35:01 +08:00
commit 1f397eca87
6258 changed files with 1487241 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
2
1 2 3 5
1 2 4 5

View File

@@ -0,0 +1,154 @@
##[$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; // 等比数列用快速幂算末项
}
}
```

View File

@@ -0,0 +1,28 @@
#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; // 这个需要快速幂
}
}

View File

@@ -0,0 +1,40 @@
#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; // 等比数列用快速幂算末项
}
}

View File

@@ -0,0 +1,21 @@
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MOD = 100003;
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 m, n;
cin >> m >> n;
cout << (qmi(m, n) - m * qmi(m - 1, n - 1) % MOD + MOD) % MOD << endl;
return 0;
}

View File

@@ -0,0 +1,37 @@
<mxfile host="Electron" modified="2023-11-13T06:26:20.100Z" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/21.3.7 Chrome/112.0.5615.204 Electron/24.5.0 Safari/537.36" etag="LmC1guNWCzKyO7h3SnAr" version="21.3.7" type="device">
<diagram name="第 1 页" id="VIb_nIt0eGq0H4E8IJp7">
<mxGraphModel dx="1418" dy="838" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="EC6tnr1v8_Lx4r9o5bla-1" value="1" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxGeometry x="100" y="240" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="EC6tnr1v8_Lx4r9o5bla-2" value="2" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
<mxGeometry x="200" y="240" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="EC6tnr1v8_Lx4r9o5bla-3" value="3" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
<mxGeometry x="300" y="240" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="EC6tnr1v8_Lx4r9o5bla-4" value="4" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
<mxGeometry x="400" y="240" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="EC6tnr1v8_Lx4r9o5bla-5" value="5" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
<mxGeometry x="500" y="240" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="EC6tnr1v8_Lx4r9o5bla-6" value="m种选择" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="90" y="300" width="60" height="30" as="geometry" />
</mxCell>
<mxCell id="EC6tnr1v8_Lx4r9o5bla-7" value="m-1种选择,需要避让1号选择的宗教" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=13;" vertex="1" parent="1">
<mxGeometry x="180" y="300" width="80" height="50" as="geometry" />
</mxCell>
<mxCell id="EC6tnr1v8_Lx4r9o5bla-9" value="m-1种选择,需要避让2号选择的宗教" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=13;" vertex="1" parent="1">
<mxGeometry x="290" y="300" width="80" height="50" as="geometry" />
</mxCell>
<mxCell id="EC6tnr1v8_Lx4r9o5bla-10" value="m-1种选择,需要避让3号选择的宗教" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=13;" vertex="1" parent="1">
<mxGeometry x="390" y="300" width="80" height="50" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

View File

@@ -0,0 +1 @@
2 3

View File

@@ -0,0 +1,82 @@
##[$AcWing$ $1290$. 越狱](https://www.acwing.com/problem/content/1292/)
### 一、题目描述
监狱有连续编号为 $1$ 到 $n$ 的 $n$ 个房间,每个房间关押一个犯人。
有 $m$ 种宗教,每个犯人可能信仰其中一种。
如果相邻房间的犯人信仰的宗教相同,就可能发生越狱。
求有多少种状态可能发生越狱。
**输入格式**
共一行,包含两个整数 $m$ 和 $n$。
**输出格式**
可能越狱的状态数,对 $100003$ 取余。
**数据范围**
$1≤m≤10^8$
$1≤n≤10^{12}$
**输入样例**
```cpp {.line-numbers}
2 3
```
**输出样例**
```cpp {.line-numbers}
6
```
**样例解释**
所有可能的 $6$ 种状态为:$(000)(001)(011)(100)(110)(111)$。
### 二、解题思路
本题可以采用容斥原理补集的思想。
考虑 $n$ 个犯人,$m$种宗教,如何安排不会导致犯罪。
第一个位置可以有 $m$ 个选择,则与第一个相邻的第二个位置就只有 $m−1$ 中选择。
考虑第 $i$ 个位置,则为了不和他左侧的 $i−1$ 位置发生冲突,一共有 $m-1$ 种选择。
![](https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/BlogImages/202311131426094.png)
因此不会导致犯罪的方案是: $m⋅(m−1)^{n−1}$
则会导致犯罪的方案是:$m^n−m⋅(m−1)^{n−1}$
计算一个数字的$n$次方,还要求取模,自然就需要使用快速幂~
<font color='red'><b>注意</b></font>
注意减法取模可能会变成负数,那么我们要把他转化正数 $(a - b + mod) \% mod$ 即可
> 这里解释下:为什么取模+减法会出现负数呢?比如$MOD=10$
> $a=13,b=5$
> $ (a\%MOD -b \% MOD) \% MOD=13\%10 - 5 \%10=3-5=-2$
> 出现负数不是我们想的结果,那就在取模时加上$MOD$就行了
### 三、实现代码
```cpp {.line-numbers}
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MOD = 100003;
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 m, n;
cin >> m >> n;
cout << (qmi(m, n) - m * qmi(m - 1, n - 1) % MOD + MOD) % MOD << endl;
return 0;
}
```

View File

@@ -0,0 +1,18 @@
#include <bits/stdc++.h>
using namespace std;
#define int long long
// 快速幂
int qmi(int a, int b) {
int res = 1;
while (b) {
cout << "b = " << (b & 1) << ", a = " << a << endl;
if (b & 1) res = res * a;
b >>= 1;
a = a * a;
}
return res;
}
signed main() {
cout << qmi(2, 10) << endl;
}

View File

@@ -0,0 +1,98 @@
## 快速幂、龟速乘总结
### 一、快速幂
求 $a^b\ mod \ p$ 的结果。
**$Code$**
```cpp {.line-numbers}
// 快速幂(不加mod)
int qmi(int a, int b) {
int res = 1;
while (b) {
if (b & 1) res = res * a;
b >>= 1;
a = a * a;
}
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;
}
```
**解释一下**:
假如我们需要计算$2^{10}$,正常的办法是
```cpp {.line-numbers}
int s = 1;
for (int i = 1; i <= 10; i++) s = s * 2;
cout << s << endl;
```
毫无疑问,这个算法是正确的。但它执行的次数是$10$次,有没有什么办法可以优化一下运算次数呢?
**优化**
将$10$进行二进制分解$(10)_{10}=(1010)_2$
这样处理后,从后向前,借助于我们熟悉的数位分离模板,就是遍历二进制的每一位。
此时,我们发现,最左面的数字$1$,权值是$8$,第三位的数字权值是$2$
同时,$2^8*2^2=2^{10}$
为什么会有这么神奇的现象呢?其实就是因为幂运算的性质造成:
$$\large 2^{10}=2^{8+2}=2^8*2^2$$
$Q:$为啥非得拆成$8+2$,为啥不拆成$7+3$呢?
就是因为类似于 **倍增** 的办法在计算中好处理呗!
$a$在代码中的使命就是:**我不管你用不用的上,反正我每次是翻倍!**
而枚举$b$的每一个数位,就是看看这个位置上的当前$a$是不是需要乘进来!幂运算的性质成功的把幂与二进制加法结合起来了。
把倍增的思路$2,4,8,16,32,...$这样长上来的,这是因为
$2^1*2^1=2^2$
$2^2*2^2=2^4$
$2^4*2^4=2^8$
$2^8*2^8=2^{16}$
$2^{16}*2^{16}=2^{32}$
**模板题** : **[$P1226$ 【模板】快速幂||取余运算](https://www.luogu.com.cn/problem/P1226)**
### 二、龟速乘
求 $a*b\ mod \ p$ 的结果,$a,b,p$ 都是 $10^{18}$ 级别。
$Code$
```cpp {.line-numbers}
// 龟速乘,快速加
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;
}
```
这东西怎么理解呢?
**举栗子吧**:
$5*6_{10}=5*(110)_2$
最右侧的$0$对就的权值是$5^1=5$ ①
右侧第二的$1$对就的权值是$5*2=10$ ②
右侧第三的$1$对就的权值是$10*2=20$ ③
而$② ③$对应的位置上有数字$1$,有效,$①$无效
结果就是$10+20=30$