一、P8723 [蓝桥杯 2020 省 AB3] 乘法表 - 洛谷
算法代码:
#include<bits/stdc++.h> // 包含标准库中的所有头文件,通常用于竞赛编程中简化代码
using namespace std; // 使用标准命名空间,避免每次调用标准库函数时都要加std::
typedef long long ll; // 定义long long类型的别名为ll,方便使用// 定义一个函数change,用于将十进制数sum转换为p进制表示的字符串
string change(ll sum, int p) {if (sum == 0) { // 如果sum为0,直接返回"0"return "0";}string result; // 定义一个空字符串result,用于存储转换后的结果while (sum > 0) { // 当sum大于0时,循环进行转换int tmp = sum % p; // 取sum对p的余数,得到当前位的值if (tmp < 10) { // 如果余数小于10,将其转换为对应的字符(0-9)result += char('0' + tmp);} else { // 如果余数大于等于10,将其转换为对应的字母(A-Z)result += char('A' + tmp - 10);}sum /= p; // 将sum除以p,继续处理下一位}reverse(result.begin(), result.end()); // 将result字符串反转,得到正确的p进制表示return result; // 返回转换后的字符串
}int main() {int p; // 定义一个整数p,表示进制cin >> p; // 从标准输入读取p的值for (int i = 1; i < p; i++) { // 外层循环,i从1到p-1for (int j = 1; j <= i; j++) { // 内层循环,j从1到ill sum = i * j; // 计算i和j的乘积// 输出i*j的结果,并将结果转换为p进制表示cout << i << "*" << j << "=" << change(sum, p) << " ";}cout << endl; // 每行结束后换行}return 0; // 程序正常结束
}
1. 确定程序的功能
-
程序的目标是生成一个乘法表,并将表中的乘积结果转换为指定的
p
进制表示。 -
例如,输入
p = 16
,程序会输出一个 16 进制的乘法表。
2. 设计核心功能
-
进制转换:需要实现一个函数,将十进制的数转换为
p
进制的字符串表示。-
例如,十进制数
15
在 16 进制下表示为"F"
。
-
-
乘法表生成:需要嵌套循环生成乘法表,并调用进制转换函数处理每个乘积。
3. 实现进制转换函数
-
函数名:
change
-
输入参数:
-
ll sum
:需要转换的十进制数。 -
int p
:目标进制。
-
-
返回值:
string
类型,表示转换后的p
进制字符串。 -
实现逻辑:
-
如果
sum
为 0,直接返回"0"
。 -
使用循环不断对
sum
取模(sum % p
),得到当前位的值。 -
根据当前位的值,将其转换为字符:
-
如果值小于 10,转换为
'0'
到'9'
。 -
如果值大于等于 10,转换为
'A'
到'Z'
。
-
-
将结果字符串反转,得到正确的
p
进制表示。
-
4. 实现乘法表生成
-
输入:从用户输入读取进制
p
。 -
逻辑:
-
使用两层循环生成乘法表:
-
外层循环控制行数(
i
从 1 到p-1
)。 -
内层循环控制列数(
j
从 1 到i
)。
-
-
计算
i * j
的乘积,并调用change
函数将其转换为p
进制。 -
输出格式为
i * j = 结果
,每行结束后换行。
-
5. 代码结构
-
头文件和命名空间:
-
使用
#include<bits/stdc++.h>
包含所有标准库头文件。 -
使用
using namespace std
简化代码。
-
-
类型别名:
-
使用
typedef long long ll
定义long long
的别名,方便使用。
-
-
进制转换函数:
-
实现
change
函数,完成十进制到p
进制的转换。
-
-
主函数:
-
读取用户输入的
p
。 -
使用嵌套循环生成乘法表,并调用
change
函数处理乘积。 -
输出结果。
-
二、P8734 [蓝桥杯 2020 国 A] 奇偶覆盖 - 洛谷
(国赛A组的题,我就直接跳过了,B组没学过这些,所以直接看大佬们的题解,等日后有实力再看)
题解:
算法代码:
#include <bits/stdc++.h> // 包含标准库中的所有头文件,通常用于竞赛编程中简化代码
#define ll long long // 定义宏,将 long long 类型简化为 ll
using namespace std; // 使用标准命名空间,避免每次调用标准库函数时都要加 std::
const int N = 2e5+5; // 定义常量 N,表示数组的最大大小int n, tot, a[N<<2]; // n: 矩形数量;tot: 离散化后的坐标数量;a: 存储所有 x 坐标
ll ans1, ans2; // ans1: 统计奇数次覆盖的面积;ans2: 统计偶数次覆盖的面积struct edge { // 定义扫描线的边结构体int y, x1, x2, k; // y: 边的 y 坐标;x1, x2: 边的左右 x 坐标;k: 边的类型(1 表示下边,-1 表示上边)
} e[N]; // e: 存储所有边struct tree { // 定义线段树结构体int l, r; // l, r: 当前节点表示的区间范围ll s1, s2, cnt; // s1: 奇数次覆盖的长度;s2: 偶数次覆盖的长度;cnt: 当前区间的覆盖次数
} t[N<<3]; // t: 线段树数组,开 8 倍空间void update(int p) { // 更新线段树节点 p 的信息if (!t[p].cnt) { // 如果当前区间没有被覆盖t[p].s1 = t[p<<1].s1 + t[p<<1|1].s1; // s1 为左右子节点的 s1 之和t[p].s2 = t[p<<1].s2 + t[p<<1|1].s2; // s2 为左右子节点的 s2 之和return;}if (t[p].cnt & 1) { // 如果当前区间被奇数次覆盖t[p].s2 = t[p<<1].s1 + t[p<<1|1].s1; // s2 为左右子节点的 s1 之和t[p].s1 = a[t[p].r+1] - a[t[p].l] - t[p].s2; // s1 为区间总长度减去 s2} else { // 如果当前区间被偶数次覆盖t[p].s1 = t[p<<1].s1 + t[p<<1|1].s1; // s1 为左右子节点的 s1 之和t[p].s2 = a[t[p].r+1] - a[t[p].l] - t[p].s1; // s2 为区间总长度减去 s1}
}void build(int p, int l, int r) { // 构建线段树t[p].l = l, t[p].r = r; // 初始化当前节点的区间范围if (l == r) return; // 如果是叶子节点,直接返回int mid = (l + r) >> 1; // 计算中点build(p<<1, l, mid); // 递归构建左子树build(p<<1|1, mid+1, r); // 递归构建右子树
}void change(int p, int l, int r, int x) { // 修改线段树的区间 [l, r],x 为修改值(1 或 -1)if (l <= t[p].l && t[p].r <= r) { // 如果当前节点被区间 [l, r] 完全覆盖t[p].cnt += x; // 更新当前节点的覆盖次数update(p); // 更新当前节点的信息return;}int mid = (t[p].l + t[p].r) >> 1; // 计算中点if (l <= mid) change(p<<1, l, r, x); // 递归修改左子树