P1009 [NOIP 1998 普及组] 阶乘之和
https://www.luogu.com.cn/problem/P1009
题目描述
用高精度计算出 S = 1 ! + 2 ! + 3 ! + ⋯ + n ! S = 1! + 2! + 3! + \cdots + n! S=1!+2!+3!+⋯+n!( n ≤ 50 n \le 50 n≤50)。
其中 !
表示阶乘,定义为
n
!
=
n
×
(
n
−
1
)
×
(
n
−
2
)
×
⋯
×
1
n!=n\times (n-1)\times (n-2)\times \cdots \times 1
n!=n×(n−1)×(n−2)×⋯×1。例如,
5
!
=
5
×
4
×
3
×
2
×
1
=
120
5! = 5 \times 4 \times 3 \times 2 \times 1=120
5!=5×4×3×2×1=120。
输入格式
一个正整数 n n n。
输出格式
一个正整数 S S S,表示计算结果。
输入输出样例 #1
输入 #1
3
输出 #1
9
说明/提示
【数据范围】
对于 100 % 100 \% 100% 的数据, 1 ≤ n ≤ 50 1 \le n \le 50 1≤n≤50。
【其他说明】
注,《深入浅出基础篇》中使用本题作为例题,但是其数据范围只有 n ≤ 20 n \le 20 n≤20,使用书中的代码无法通过本题。
如果希望通过本题,请继续学习第八章高精度的知识。
NOIP1998 普及组 第二题
AC Code
#include <bits/stdc++.h>
using namespace std;
int Add[109];
int Mul[109];
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int n;
cin >> n;
Add[0] = 1;
Mul[0] = 1;
int i,j;
for(i=2;i<=n;i++){
for(j=0;j<100;j++){
Mul[j]*=i;
}
for(j=0;j<100;j++){
if (Mul[j]>9){
Mul[j+1] += Mul[j]/10;
Mul[j]%=10;
}
}
for(j=0;j<100;j++){
Add[j]+=Mul[j];
if (Add[j]>9) {
Add[j+1] += Add[j]/10;
Add[j]%=10;
}
}
}
for(i=100;i>=0&&Add[i]==0;i--);
for(j=i;j>=0;j--){
cout << Add[j];
}
return 0;
}
B3977 [语言月赛 202405] 更好的交换
https://www.luogu.com.cn/problem/B3977
题目描述
小 S 有一个奇怪的机关拼图。这个拼图可以看作一个 n n n 行 n n n 列的方阵 A A A,第 i i i 行第 j j j 列的位置上有一个正整数 A i , j A_{i, j} Ai,j。
与寻常拼图不同的是,这个机关拼图上的数字不能随意移动,必须按照如下规则之一操作:
- 选择拼图上的第 x x x 行和第 y y y 行,交换这两行;
- 选择拼图上的第 x x x 列和第 y y y 列,交换这两列。
为了复原这个拼图,小 S 将会操作共 m m m 次,每次操作格式如下:
1 x y
,表示交换第 x x x 行和第 y y y 行;0 x y
,表示交换第 x x x 列和第 y y y 列;
请你输出复原后的拼图。
输入格式
第一行,两个正整数
n
n
n 和
m
m
m,分别表示拼图的行数、列数和总操作次数。
接下来
n
n
n 行,每行
n
n
n 个正整数
A
i
,
j
A_{i, j}
Ai,j,表示拼图上第
i
i
i 行,第
j
j
j 列上的数字。
接下来
m
m
m 行,每行三个正整数
o
p
,
x
,
y
op, x, y
op,x,y,其中
o
p
op
op 表示操作类型,
x
,
y
x, y
x,y 代表被操作的行号或列号。
输出格式
输出共 n n n 行,每行 n n n 个正整数,表示复原后的拼图。
输入输出样例 #1
输入 #1
3 2
4 5 6
3 2 1
9 8 7
0 2 3
0 2 2
输出 #1
4 6 5
3 1 2
9 7 8
输入输出样例 #2
输入 #2
3 2
11 12 13
21 22 23
31 32 33
1 2 3
0 2 3
输出 #2
11 13 12
31 33 32
21 23 22
输入输出样例 #3
输入 #3
4 4
12 32 42 82
53 43 34 98
90 32 42 53
37 17 88 10
0 2 4
1 2 4
0 1 4
1 1 3
输出 #3
32 53 42 90
17 10 88 37
32 82 42 12
43 98 34 53
说明/提示
样例 1 解释
第一次操作,交换了第 2 2 2 列和第 3 3 3 列;第二次操作,没有发生变化。
样例 2 解释
第一次操作,交换第
2
2
2 行和第
3
3
3 行,拼图变为:
11
12
13
31
32
33
21
22
23
\begin{aligned} 11 \ 12 \ 13\\ \textcolor{red}{31 \ 32 \ 33}\\ \textcolor{blue}{21 \ 22 \ 23} \end{aligned}
11 12 1331 32 3321 22 23
第二次操作,交换第
2
2
2 列和第
3
3
3 列,拼图变为:
11
13
12
31
33
32
21
23
22
\begin{aligned} 11 \ \textcolor{red}{13} \ \textcolor{blue}{12} \\ 31 \ \textcolor{red}{33} \ \textcolor{blue}{32} \\ 21 \ \textcolor{red}{23} \ \textcolor{blue}{22} \end{aligned}
11 13 1231 33 3221 23 22
数据范围
对于前
30
%
30 \%
30% 的数据,保证每一行数字相同;
对于前
60
%
60 \%
60% 的数据,保证
1
≤
m
≤
3
×
1
0
3
1 \leq m \leq 3 \times 10^3
1≤m≤3×103。
对于
100
%
100 \%
100% 的数据,保证
1
≤
m
≤
1
0
6
,
1
≤
n
,
A
i
,
j
≤
1
0
3
,
1
≤
x
,
y
≤
n
1 \leq m \leq 10^6, 1 \leq n, A_{i, j} \leq 10^3, 1 \leq x, y \leq n
1≤m≤106,1≤n,Ai,j≤103,1≤x,y≤n,
0
≤
o
p
≤
1
0 \leq op \leq 1
0≤op≤1。
解题思路
不难发现,行和列之间的修改是无关的。我们可以将行和列的操作分开处理。
现在我们假设只有行操作,没有列操作该如何处理。
实际上,我们可以不用真的去交换每一行。考虑用一个数组 row[i]
来表示当前第 i
行里所存储的是初始的哪一行。那么,对于一次交换 x
行和 y
行的操作,我们只需要交换 row[x]
和 row[y]
即可。
同理,如果只有列操作,没有行操作,该如何处理呢?可以开一个 col[i]
数组,表示当前第 i
列里存储的是初始的哪一列,然后也只需要交换 col[x]
和 col[y]
即可。
由于行和列的操作互不相干,所以以上两个方法可以同时进行。也就是说,我们只要用数组 row
和 col
来代替每次的修改就可以了:
接下来考虑如何输出答案。在用二重循环枚举行和列时,直接输出 a[row[i]][col[j]]
即可:
AC Code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3+9;
int a[N][N];
int row[N],col[N];
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int n,m;
cin >> n >> m;
for(int i=1;i<=n;i++){
row[i] = i;
}
for(int i=1;i<=n;i++){
col[i]=i;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin >> a[i][j];
}
}
while(m--){
int op;
cin >> op;
int x,y;
cin >> x >> y;
if(op == 1){
swap(row[x],row[y]);
}
else{
swap(col[x],col[y]);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cout << a[row[i]][col[j]] << ' ';
}
cout << endl;
}
return 0;
}