程序设计笔记
CXX
常见快速类型转换
1.int ->string
#include <string>
#include <iostream>
int num = 123;
std::string str = std::to_string(num);
std::cout << str << std::endl; // 输出 "123"
2.string -> int
#include <sstream>
int str_to_int(string str_) {
int num;
std::stringstream ss(str_);
ss >> num; // 从字符串流读取到 int
return num;
//0123 -> 123
}
递归写法
题目:递归左右区间,单个元素返回值
偶数区间返回L*R,奇数返回|L-R| * mid * |L+R|
使用带返回值的写法即可
lld dfs(const vector<lld> s) {
//
if (s.size() == 1)
return s[0] mod MOD_N;
lld size_ = s.size() / 2;
if (s.size() % 2 == 0) {
vector<lld> s1(s.begin(), s.begin() + size_);
vector<lld> s2(s.begin() + size_, s.end());
lld L = dfs(s1);
lld R = dfs(s2);
return mod_mul(L, R);
}
else {
vector<lld> s1(s.begin(), s.begin() + size_);
vector<lld> s2(s.begin() + size_ + 1, s.end());
lld mid = s[size_];
lld L = dfs(s1);
lld R = dfs(s2);
lld LR = mod_mul(std::abs(mod_add(L, -R)), mod_add(L, R));
return mod_mul(mid, LR);
}
}
void solve() {
int n;
cin >> n;
vector<lld> s(n);
for (auto &i : s)
cin >> i;
sum = dfs(s);
std::cout << sum << ENDL;
}
STL 常见用法
String
快速清空数组为 0/-1,但是不建议为其他除了 0/-1 之外的数字
#include <cstring> // for memset
int arr[1000];
memset(arr, 0, sizeof(arr)); // 全部置 0
1.vector
区间表示法:[begin, end),即左闭右开区间
//从已有vector创建新的vector
bool check(vector<int> a) {
int n = a.size();
for (int pos = 1; pos < n; ++pos) {
vector<lld> left(a.begin(), a.begin() + pos);
// left创建了从[start,pos)的区间
vector<lld> right(a.begin() + pos, a.end());
// right创建了从[pos,end)的区间
}
}
2.哈希表和红黑树实现的容器
unorder_set
特点:无序集合,存储唯一的元素,不允许重复
#include <unordered_set>
using std::unordered_set;
int main() {
unordered_set<int> s1; // 空集合
unordered_set<int> s2 = {1, 2, 3}; // 初始化列表
unordered_set<int> s3(s2); // 拷贝构造
// 插入元素
s1.insert(4); // 插入单个元素
s1.insert({5, 6, 7}); // 插入多个元素
s1.emplace(8); // 原地构造元素
// 判断元素是否存在
if (s1.find(5) != s1.end()) {
// 元素存在
}
// 使用 count 检查存在性(返回0或1)
if (s1.count(5)) {
// 元素存在
}
// 删除元素
s1.erase(5); // 删除值为5的元素
s1.erase(s1.begin()); // 删除第一个元素(任意)
s1.clear(); // 清空集合
// 获取容量
bool isEmpty = s1.empty();
size_t size = s1.size();
// 遍历容器
for (int num : s1) {
cout << num << " ";
}
for (auto it = s1.begin(); it != s1.end(); ++it) {
cout << *it << " ";
}
// 获取某个元素的位置 使用迭代器
auto it = s1.find(5);
if (it != s1.end()) {
// 可以通过*it访问元素
}
}
2.unordered_multiset
无序多重集合,允许存储重复元素
#include <iostream>
#include <unordered_set>
using std::unordered_multiset;
int main() {
// 初始化
unordered_multiset<int> s1; // 空集合
unordered_multiset<int> s2 = {1, 2, 2, 3}; // 初始化列表,允许重复
unordered_multiset<int> s3(s2); // 拷贝构造
// 插入元素
s1.insert(4); // 插入单个元素
s1.insert({5, 5, 6}); // 插入多个元素,允许重复
s1.emplace(7); // 原地构造元素
// 判断元素是否存在
if (s1.find(5) != s1.end()) {
std::cout << "元素 5 存在\n";
}
// 使用 count 检查存在性及出现次数
if (s1.count(5)) {
std::cout << "元素 5 出现 " << s1.count(5) << " 次\n";
}
// 删除元素
s1.erase(5); // 删除所有值为 5 的元素
s1.erase(s1.begin()); // 删除任意一个元素
s1.clear(); // 清空集合
// 获取容量
bool isEmpty = s1.empty();
size_t size = s1.size();
// 遍历容器
for (int num : s2) {
std::cout << num << " ";
}
std::cout << "\n";
for (auto it = s2.begin(); it != s2.end(); ++it) {
std::cout << *it << " ";
}
std::cout << "\n";
// 获取某个元素的位置 使用迭代器
auto it = s2.find(2);
if (it != s2.end()) {
// 成功找到会输出2
std::cout << *it << "\n";
}
return 0;
}
3.unordered_map
无序键值对映射,键唯一,基于哈希表实现
#include <iostream>
#include <unordered_map>
using std::unordered_map;
int main() {
// 初始化
unordered_map<int, std::string> m1; // 空映射
unordered_map<int, std::string> m2 = {{1, "one"}, {2, "two"}}; // 初始化列表
unordered_map<int, std::string> m3(m2); // 拷贝构造
// 插入元素
m1.insert({4, "four"}); // 插入单个键值对
m1.insert({{5, "five"}, {6, "six"}}); // 插入多个键值对
m1.emplace(7, "seven"); // 原地构造键值对
// 判断键是否存在
if (m1.find(5) != m1.end()) {
std::cout << "键 5 存在\n";
}
// 使用 count 检查键存在性(返回 0 或 1)
if (m1.count(5)) {
std::cout << "键 5 存在\n";
}
// 使用 operator[] 访问或插入
m1[8] = "eight"; // 如果键 8 不存在,则插入
// 删除元素
m1.erase(5); // 删除键为 5 的键值对
m1.erase(m1.begin()); // 删除任意一个键值对
m1.clear(); // 清空映射
// 获取容量
bool isEmpty = m1.empty();
size_t size = m1.size();
// 遍历容器
for (const auto& pair : m2) {
std::cout << pair.first << ": " << pair.second << " ";
}
std::cout << "\n";
for (auto it = m2.begin(); it != m2.end(); ++it) {
std::cout << it->first << ": " << it->second << " ";
}
std::cout << "\n";
// 获取某个键的位置 使用迭代器
auto it = m2.find(2);
if (it != m2.end()) {
std::cout << "找到键值对: " << it->first << ": " << it->second << "\n";
}
return 0;
}
unordered_multimap
无序键值对映射,允许重复键,基于哈希表实现
键可以重复,同一键可对应多个值:
#include <iostream>
#include <unordered_map>
using std::unordered_multimap;
int main() {
// 初始化
unordered_multimap<int, std::string> mm1; // 空映射
unordered_multimap<int, std::string> mm2 = {{1, "one"}, {1, "uno"}, {2, "two"}}; // 初始化列表
unordered_multimap<int, std::string> mm3(mm2); // 拷贝构造
// 插入元素
mm1.insert({4, "four"}); // 插入单个键值对
mm1.insert({{5, "five"}, {5, "cinco"}}); // 插入多个键值对,允许重复键
mm1.emplace(6, "six"); // 原地构造键值对
// 判断键是否存在
if (mm1.find(5) != mm1.end()) {
std::cout << "键 5 存在\n";
}
// 使用 count 检查键存在性及出现次数
if (mm1.count(5)) {
std::cout << "键 5 出现 " << mm1.count(5) << " 次\n";
}
// 删除元素
mm1.erase(5); // 删除所有键为 5 的键值对
mm1.erase(mm1.begin()); // 删除任意一个键值对
mm1.clear(); // 清空映射
// 获取容量
bool isEmpty = mm1.empty();
size_t size = mm1.size();
// 遍历容器
for (const auto& pair : mm2) {
std::cout << pair.first << ": " << pair.second << " ";
}
std::cout << "\n";
for (auto it = mm2.begin(); it != mm2.end(); ++it) {
std::cout << it->first << ": " << it->second << " ";
}
std::cout << "\n";
// 获取某个键的位置 使用迭代器
auto it = mm2.find(1);
if (it != mm2.end()) {
std::cout << "找到键值对: " << it->first << ": " << it->second << "\n";
}
// 获取所有键为 1 的键值对
auto range = mm2.equal_range(1);
for (auto i = range.first; i != range.second; ++i) {
std::cout << i->first << ": " << i->second << " ";
}
std::cout << "\n";
return 0;
}
基于红黑树实现的容器
set:有序集合,存储唯一元素
#include <iostream>
#include <set>
using std::set;
int main() {
// 初始化
set<int> s1; // 空集合
set<int> s2 = {1, 2, 3}; // 初始化列表
set<int> s3(s2); // 拷贝构造
// 插入元素
s1.insert(4); // 插入单个元素
s1.insert({5, 6, 7}); // 插入多个元素
s1.emplace(8); // 原地构造元素
// 判断元素是否存在
if (s1.find(5) != s1.end()) {
std::cout << "元素 5 存在\n";
}
// 使用 count 检查存在性(返回 0 或 1)
if (s1.count(5)) {
std::cout << "元素 5 存在\n";
}
// 删除元素
s1.erase(5); // 删除值为 5 的元素
s1.erase(s1.begin()); // 删除第一个元素(最小值)
s1.clear(); // 清空集合
// 获取容量
bool isEmpty = s1.empty();
size_t size = s1.size();
// 遍历容器
for (int num : s2) {
std::cout << num << " ";
}
std::cout << "\n";
for (auto it = s2.begin(); it != s2.end(); ++it) {
std::cout << *it << " ";
}
std::cout << "\n";
// 获取某个元素的位置 使用迭代器
auto it = s2.find(2);
if (it != s2.end()) {
std::cout << "找到元素: " << *it << "\n";
}
return 0;
}
multiset:有序多重集合,允许重复元素
#include <iostream>
#include <set>
using std::multiset;
int main() {
// 初始化
multiset<int> s1; // 空集合
multiset<int> s2 = {1, 2, 2, 3}; // 初始化列表,允许重复
multiset<int> s3(s2); // 拷贝构造
// 插入元素
s1.insert(4); // 插入单个元素
s1.insert({5, 5, 6}); // 插入多个元素,允许重复
s1.emplace(7); // 原地构造元素
// 判断元素是否存在
if (s1.find(5) != s1.end()) {
std::cout << "元素 5 存在\n";
}
// 使用 count 检查存在性及出现次数
if (s1.count(5)) {
std::cout << "元素 5 出现 " << s1.count(5) << " 次\n";
}
// 删除元素
s1.erase(5); // 删除所有值为 5 的元素
s1.erase(s1.begin()); // 删除第一个元素(最小值)
s1.clear(); // 清空集合
// 获取容量
bool isEmpty = s1.empty();
size_t size = s1.size();
// 遍历容器
for (int num : s2) {
std::cout << num << " ";
}
std::cout << "\n";
for (auto it = s2.begin(); it != s2.end(); ++it) {
std::cout << *it << " ";
}
std::cout << "\n";
// 获取某个元素的位置 使用迭代器
auto it = s2.find(2);
if (it != s2.end()) {
std::cout << "找到元素: " << *it << "\n";
}
return 0;
}
map:序键值对映射,键唯一
#include <iostream>
#include <map>
using std::map;
int main() {
// 初始化
map<int, std::string> m1; // 空映射
map<int, std::string> m2 = {{1, "one"}, {2, "two"}}; // 初始化列表
map<int, std::string> m3(m2); // 拷贝构造
// 插入元素
m1.insert({4, "four"}); // 插入单个键值对
m1.insert({{5, "five"}, {6, "six"}}); // 插入多个键值对
m1.emplace(7, "seven"); // 原地构造键值对
// 判断键是否存在
if (m1.find(5) != m1.end()) {
std::cout << "键 5 存在\n";
}
// 使用 count 检查键存在性(返回 0 或 1)
if (m1.count(5)) {
std::cout << "键 5 存在\n";
}
// 使用 operator[] 访问或插入
m1[8] = "eight"; // 如果键 8 不存在,则插入
// 删除元素
m1.erase(5); // 删除键为 5 的键值对
m1.erase(m1.begin()); // 删除第一个键值对(最小键)
m1.clear(); // 清空映射
// 获取容量
bool isEmpty = m1.empty();
size_t size = m1.size();
// 遍历容器
for (const auto& pair : m2) {
std::cout << pair.first << ": " << pair.second << " ";
}
std::cout << "\n";
for (auto it = m2.begin(); it != m2.end(); ++it) {
std::cout << it->first << ": " << it->second << " ";
}
std::cout << "\n";
// 获取某个键的位置 使用迭代器
auto it = m2.find(2);
if (it != m2.end()) {
std::cout << "找到键值对: " << it->first << ": " << it->second << "\n";
}
return 0;
}
multimap:
有序键值对映射,允许重复键,
#include <iostream>
#include <map>
using std::multimap;
int main() {
// 初始化
multimap<int, std::string> mm1; // 空映射
multimap<int, std::string> mm2 = {{1, "one"}, {1, "uno"}, {2, "two"}}; // 初始化列表
multimap<int, std::string> mm3(mm2); // 拷贝构造
// 插入元素
mm1.insert({4, "four"}); // 插入单个键值对
mm1.insert({{5, "five"}, {5, "cinco"}}); // 插入多个键值对,允许重复键
mm1.emplace(6, "six"); // 原地构造键值对
// 判断键是否存在
if (mm1.find(5) != mm1.end()) {
std::cout << "键 5 存在\n";
}
// 使用 count 检查键存在性及出现次数
if (mm1.count(5)) {
std::cout << "键 5 出现 " << mm1.count(5) << " 次\n";
}
// 删除元素
mm1.erase(5); // 删除所有键为 5 的键值对
mm1.erase(mm1.begin()); // 删除第一个键值对(最小键)
mm1.clear(); // 清空映射
// 获取容量
bool isEmpty = mm1.empty();
size_t size = mm1.size();
// 遍历容器
for (const auto& pair : mm2) {
std::cout << pair.first << ": " << pair.second << " ";
}
std::cout << "\n";
for (auto it = mm2.begin(); it != mm2.end(); ++it) {
std::cout << it->first << ": " << it->second << " ";
}
std::cout << "\n";
// 获取某个键的位置 使用迭代器
auto it = mm2.find(1);
if (it != mm2.end()) {
std::cout << "找到键值对: " << it->first << ": " << it->second << "\n";
}
// 获取所有键为 1 的键值对
auto range = mm2.equal_range(1);
for (auto i = range.first; i != range.second; ++i) {
std::cout << i->first << ": " << i->second << " ";
}
std::cout << "\n";
return 0;
}
位运算
使用 01 串枚举所有的可能,根据 01 来决定如何运算
bool f(int n) {
for (int i = 0; i < 1 << (n - 1); ++i) {
// 0-2^n-1-1
//
for (int j = 1; j < n; ++j) {
// 检查j的第 j-1 位是否为 1
// 如果是 则为 true 进入if
// 否则进入 else
if (i & 1 << (j - 1)) {
return false;
// body
} else {
return false;
// body
}
}
}
return false;
}
查找类
高效查找两个固定数组的共同元素
哈希
//哈希
#include <unordered_set>
#include <vector>
long long count_ele(const std::vector<long long> &a,
const std::vector<long long> &b) {
std::unordered_set<long long> set_a(a.begin(),
a.end()); // 将数组 a 存入哈希表
long long count = 0;
for (int num : b) {
if (set_a.count(num)) { // 检查 b 的元素是否在 a 中存在
count++;
}
}
return count;
}
双指针实现
long long count_elements(std::vector<long long> &a, std::vector<long long> &b) {
std::sort(a.begin(), a.end());
std::sort(b.begin(), b.end());
long long i = 0, j = 0, count = 0;
while (i < a.size() && j < b.size()) {
if (a[i] == b[j]) {
count++;
i++;
j++;
} else if (a[i] < b[j]) {
i++;
} else {
j++;
}
}
return count;
}
双指针
排序后记录出现次数大于等于 2 的元素个数
// 1 1 1 2 2 3 sum=2
int sum = 0;
vector<int> s;
int n = s.size();
for (int i = 0, j = 1; j < n;) {
while (j < n and s[i] == s[j])
j++;
if (j - i >= 2) {
sum++;
}
i = j;
}
双指针算矩形面积
数论
gcd lcm
lld gcd(lld x, lld y) {
if (y == 0) {
return x;
} else {
return gcd(y, x % y);
}
}
lld lcm(lld x, lld y) {
return x * y / gcd(x, y);
}
T 个询问区间[L,R]多少个素数
const int MX = 1e5 + 10; // 只需预处理到sqrt(1e9)≈31623
vector<int> p; // 存储小素数
// 预处理所有小于√R的素数 存储在数组p
void init() {
// np[i]=true表示i不是素数
vector<bool> np(MX);
np[0] = np[1] = true;
for (int i = 2; i < MX; ++i) {
if (!np[i])
p.push_back(i);
for (int j = 0; j < p.size() && i * p[j] < MX; ++j) {
np[i * p[j]] = true;
if (i % p[j] == 0)
break;
}
}
}
// 分段筛法查询区间[L,R]的素数个数
lld qry(lld L, lld R) {
if (L > R)
return 0;
if (R < 2)
return 0;
// 标记区间[L,R]内的数是否为素数
vector<bool> seg(R - L + 1, true);
for (lld prime : p) {
if (prime * prime > R)
break;
lld start = max(prime * prime, (L + prime - 1) / prime * prime);
for (lld j = start; j <= R; j += prime) {
seg[j - L] = false;
}
}
if (L == 1)
seg[0] = false; // 1不是素数
lld cnt = 0;
for (bool is_prime : seg) {
cnt += is_prime;
}
return cnt;
}
int main() {
init();
int T = 1;
cin >> T;
while (T--) {
lld L, R;
cin >> L >> R;
cout << qry(L, R) << std::endl;
}
return 0;
}
附录
ASCII 对照表
//number
0: 48
b: 49
...
9: 57
//快速把char输出为int
cout << x - 48 << endl;
//字母
a: 97
b: 98
...
z: 122
头文件
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <functional> // 需要包含这个头文件以使用 std::greater
#include <iostream>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <unordered_set>
#include <vector>
#define lld long long // long long 的 printf 占位符是 lld
#define ENDL '\n' // 将 endl 替换为 \n 取消缓冲区
#define mod %
const lld N = 1e5 + 9;
const lld MOD_N = 1e9 + 7;
const lld MAX_ = 1e9;
using std::cin;
using std::cout;
using std::priority_queue;
using std::queue;
using std::set;
using std::stack;
using std::string;
using std::unordered_set;
using std::vector;
// 大根堆 小根堆
std::priority_queue<int, std::vector<int>, std::greater<int>> min_heap;
std::priority_queue<int> max_heap;
// 自定义排序
auto cmp = [](int a, int b) {
if (a % 2 == b % 2)
return a > b; // 同奇偶时降序
return a % 2 < b % 2; // 奇数优先
};
std::priority_queue<int, vector<int>, decltype(cmp)> custom_heap(cmp);
// 按照年龄
struct Person {
string name;
int age;
};
auto cmp_ = [](Person a, Person b) {
return a.age > b.age;
// 注意是 >,表示小的在前
// 小根堆年龄
// 也就是实际是20 25 30
};
priority_queue<Person, vector<Person>, decltype(cmp_)> age_heap(cmp_);
//同理其他的容器 set
std::set<lld, decltype(cmp)> st(cmp);
lld safe_mod(lld x) {
// 对负数取mod 保证结果在 [0, MOD-1]
return (x % MOD_N + MOD_N) % MOD_N;
}
// 取模加法 (a + b) % MOD_N
lld mod_add(lld a, lld b) { return (a mod MOD_N + b mod MOD_N) mod MOD_N; }
// 取模乘法 (a * b) % MOD_N
lld mod_mul(lld a, lld b) { return (a mod MOD_N * b mod MOD_N) mod MOD_N; }
// 取模快速幂 (a^b) % MOD_N
lld mod_pow(lld a, lld b) {
lld res = 1;
while (b > 0) {
if (b & 1)
res = mod_mul(res, a);
a = mod_mul(a, a);
b >>= 1;
}
return res;
}
// gcd 和 lcm
lld gcd(lld x, lld y) {
if (y == 0) {
return x;
} else {
return gcd(y, x % y);
}
}
lld lcm(lld x, lld y) { return x * y / gcd(x, y); }
inline int read();
inline void write(lld x);
bool check(lld mid) {
// **body**
}
int bin_sh(lld L, lld R) {
lld mid = L + (R - L) / 2;
while (L <= R) {
mid = L + (R - L) / 2;
if (check(mid)) {
L = mid + 1; // 调整左边界
} else {
R = mid - 1;
}
}
return mid;
}
void solve() {
// body
}
int main() {
std::ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T = 1;
cin >> T;
while (T--) {
solve();
}
}
// lld read 和 lld 类型的 write
inline lld read() {
lld x = 0, f = 1;
char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-')
f = -1;
ch = getchar();
}
while (isdigit(ch)) {
x = x * 10 + (ch - '0');
ch = getchar();
}
return x * f;
}
//修改参数类型即可
inline void write(lld x) {
if (x < 0)
putchar('-'), x = -x;
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}

浙公网安备 33010602011771号