当前位置: 首页 > news >正文

CCF csp认证 小白必看

c++支持到C++17(还是更高?);所以学一些封装好的函数功能是必要的---比如STL里的函数;

因为可携带纸质资料,建议打印带入,需要时可翻阅。

【题目概述:】

0-devc++环境配置

配置好你常用的编译版本:

想要调试记得开启下选项:

0.1小tips:

评测机一般 5*10^8 /s;算复杂度比较一下,同数量级就优化常数;

开辟静态数组的小技巧:开辟静态数组的内存空间时,往往将空间设置比真实大小大一点,来防止访问越界问题。例如,上述代码可以只设计一个空间大小为10000的数组,但是往往喜欢比真是大小多10,变为大小为10010的数组。

cin和scanf的对比:cin相对于scanf来说语法更加简单,但是其效率比scanf更低。一个经验是当输入个数小于100000时两者均可,超过100000时从效率考虑使用scanf更加合理。

基本上都会包含的头文件:基本上所有的竞赛代码都会包含<iostream>以及<cstring>和<algorithm>三个头文件,因此可以提前写上。

0.1.1 对于统计字符个数【尤其是字母个数】:

不用开结构体,可以直接根据字母对应的ASCII码(一个整数),作为数组的下标去存储。即 用cnt[int(A)]这种直接进行计数;

比如,A-Z,26个,我统计出Z有3个。而int( ‘Z’ ) =120; 我直接arr[ int ( 'z' )]++;  即统计了个数;

示例代码:

0.1.2  对于子串重复查找:

类似KMP的思想,不需要重复回溯。比如string  str1="abc.....zabcd";(大小为26+4 = 30);

比如我找‘d’;第一次找到是在下标=3;那么下一次从3的下一位置4开始找,而不需从第2位;

【这里如果是一个字串"abc",就很明显,比如首次找到匹配是在小标  = 10;也就同时说明了0-9的位置是不匹配的,下一次要从10+1开始,所以下面是pos  = found +1 】

0.1.3 除法涉及浮点数,为避免误差,判断时,挪为另一边,变成乘法;

0.1.4 第二题一般后30%涉及优化: 基本都是 前缀和;

预处理前i项和:

一维前缀和: 求sum( A[i]~A[j] )  ,用pre_sum(j)- pre_sum(i);

        前缀和矩阵本身的计算?  --类似dp;  如下

        学会用递归【即 sum _i = sum_i-1 + a这种,避免每一项都要重新计算;如下】

e.g. 202012 -2 安全阈值:

等效变形---0/1的情况与个数的关系;

前i项里0 的个数    =   i- (1的计数—而1的计数就是求和结果;)

从i项起到最后1的个数 = 01总个数 - 0的个数[0的个数用相减就行]

从第i+n项到第i项之间1的个数 == n- (这之间0的个数)

1-输入输出

#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>
#include <iterator>
#include <boost/tokenizer.hpp> // 如果使用 Boost 库using namespace std;int main() {
12    // 读取一个整数
13    int a;
14    cin >> a;
15    cout << "a: " << a << endl;
16
17    // 读取一个字符串
18    string s;
19    cin >> s;
20    cout << "s: " << s << endl;
21
22    // 读取一行文本(包括空格)
23    string line;
24    getline(cin, line);
25    cout << "Line: " << line << endl;
26
27    // 读取多个整数到 vector 中
28    int n;
29    cin >> n;
30    vector<int> nums(n);
31    for (int i = 0; i < n; ++i) {
32        cin >> nums[i];
33    }
34    cout << "Numbers: ";
35    copy(nums.begin(), nums.end(), ostream_iterator<int>(cout, " "));
36    cout << endl;
37
38    // 读取多行文本到 vector<string> 中
39    int numLines;
40    cin >> numLines;
41    vector<string> lines(numLines);
42    for (int i = 0; i < numLines; ++i) {
43        getline(cin, lines[i]);
44    }
45    cout << "Lines: ";
46    for (const auto& line : lines) {
47        cout << line << endl;
48    }
49说明
1.	读取一个整数:
o	使用 cin >> a 读取一个整数 a。
2.	读取一个字符串:
o	使用 cin >> s 读取一个字符串 s。
3.	读取一行文本(包括空格):
o	使用 getline(cin, line) 读取一行文本,包括空格。
4.	读取多个整数到 vector 中:
o	使用 for 循环和 cin 读取多个整数到 vector<int> 中。
5.	读取多行文本到 vector<string> 中:
o	使用 for 循环和 getline 读取多行文本到 vector<string> 中。2. getline()
//getline() 是 C++ 标准库中的一个函数,用于从流中读取一行文本,直到遇到换行符。它可以安全地读取一行文本,并且不会导致缓冲区溢出。【分隔符本身不会被存储在 str 中】std::istream& getline(std::istream& is, std::string& str, char delimiter = '\n');
参数
•    is:输入流对象,通常是 std::cin。
•    str:用于存储输入字符串的 std::string 对象。
•    delimiter:分隔符,默认为换行符 ('\n')。
返回值
•    成功读取字符串时返回 is 的引用。
•    读取失败时,std::cin 的状态将变为 std::ios_base::failbit。
注意事项
•    安全性:getline() 是安全的,因为它会自动管理缓冲区的大小。
•    方便性:getline() 可以读取包含空格的字符串,并且可以自定义分隔符。
•    int main() {
•    5    std::string line;
•    6
•    7    std::cout << "Enter a line: ";
•    8    if (std::getline(std::cin, line)) {
•    9        std::cout << "You entered: " << line << std::endl;
•    10    } else {
•    11        std::cout << "Failed to read input." << std::endl;
•    12    }•       while (std::getline(std::cin, line, ',')) {
•          fields.push_back(line);
•       }

2-STL: C++ 中一个强大的库

Standard Template Library,标准模板库

2.1 set #include <set>


1.    有序性:
        o    std::set 中的元素是有序的,默认按照元素的自然排序进行排序(例如,数字从小到大,字符串按字典序排列)。
        o    可以指定自定义比较器来改变排序规则。
2.    唯一性:
        o    std::set 中不允许有重复的元素。如果尝试插入重复的元素,插入操作将失败。
3.    插入与删除:
        o    插入操作通常是 O(log n) 的时间复杂度,因为 std::set 内部使用红黑树实现。
        o    删除操作也是 O(log n) 的时间复杂度。

std::set 的常用操作


创建 std::set
4int main() {
5    std::set<int> mySet; // 创建一个空的 set
6    std::set<std::string> stringSet; // 创建一个空的 string set
插入元素
1mySet.insert(10); // 插入一个元素
2mySet.insert({20, 30}); // 插入多个元素
删除元素
1mySet.erase(mySet.find(10)); // 删除一个元素
2mySet.erase(mySet.begin(), mySet.end()); // 删除指定范围内的元素
查找元素
1auto it = mySet.find(10); // 查找元素
2if (it != mySet.end()) {
3    std::cout << "Element found: " << *it << std::endl;
4} else {
5    std::cout << "Element not found." << std::endl;
6}
判断元素是否存在
1bool contains = mySet.count(10); // 判断元素是否存在
获取元素数量
1size_t size = mySet.size(); // 获取元素数量
清空容器
1mySet.clear(); // 清空容器
迭代器遍历
1for (const auto& elem : mySet) {
2    std::cout << elem << " ";
3}
4std::cout << std::endl;
5
6for (auto it = mySet.begin(); it != mySet.end(); ++it) {
7    std::cout << *it << " ";
8}
9std::cout << std::endl;
自定义比较器
你还可以使用自定义比较器来改变 std::set 的排序规则。
4struct CustomComparator {
5    bool operator()(const std::string& lhs, const std::string& rhs) const {
6        return lhs.size() < rhs.size(); // 按字符串长度排序
7    }
8};
9
10int main() {
11    std::set<std::string, CustomComparator> stringSet;
12    stringSet.insert("world");
13    stringSet.insert("hello");
14    stringSet.insert("hi");
15
16    for (const auto& elem : stringSet) {
17        std::cout << elem << " ";
18    }
19    std::cout << std::endl;
20
21    return 0;
22}
性能分析
1.	时间复杂度:
o	插入:O(log n)
o	删除:O(log n)
o	查找:O(log n)
2.	空间复杂度:
o	O(n),其中 n 是容器中的元素数量。int main() {
5    std::set<int> mySet = {10, 20, 30, 40, 50};
6    
7    // 使用迭代器访问元素
8    for (auto it = mySet.begin(); it != mySet.end(); ++it) {
9        std::cout << *it << " ";
10    }
11    std::cout << std::endl;
13    // 使用 range-based for 循环访问元素
14    for (const auto& elem : mySet) {
15        std::cout << elem << " ";
16    }
17    std::cout << std::endl;
19    // 查找元素
20    auto it = mySet.find(30);
21    if (it != mySet.end()) {
22        std::cout << "Found element: " << *it << std::endl;
23    }/*set(集合),是一个内部自动有序且不含重复元素的容器
set只能通过迭代器(iterator)访问原本无序的元素,被插入set集合后,set内部的元素自动递增排序,并且自动去除了重复元素。
注意:除了vector和string之外的STL容器都不支持*(it+i)的访问方式,因此只能按照如下方式枚举:
*/#include <iostream>
#include <set>
using namespace std;
int main()
{set<int> st;st.insert(5);st.insert(2);st.insert(6);for (set<int>::iterator it = st.begin(); it != st.end(); it++){cout << *it << endl;}return 0;
}insert(item):插入元素
find(value):返回的是set中value所对应的迭代器,也就是value的指针(地址)
erase():删除单个元素、删除一个区间内的所有元素
erase(it):其中it为所需要删除元素的迭代器。时间复杂度为O(1)。可以结合find()函数来使用
erase(value):value为所需要删除元素的值
erase(iteratorBegin , iteratorEnd):删除一个区间内的所有元素
size():获得set内元素的个数
#include<set>
using namespace std;set<类型名> 变量名;
set<int> name;
set<double> name;
set<char> name;
set<struct node> name;
set<set<int> > name;//注意:> >之间要加空格
set<类型名> array[SIZE];

2.2 Vector#include <vector>


std::vector 是一种动态数组,非常适合需要频繁添加或删除元素的场景。
o    std::vector 支持随机访问,可以通过下标(索引)快速访问元素。


示例代码
下面是一个完整的示例代码,演示了 std::vector 的常见操作。
1#include <iostream>
2#include <vector>
3#include <algorithm> // 用于 std::find5int main() {// 创 建 vector
5    std::vector<int> myVector; // 创建一个空的 vector
6    std::vector<std::string> stringVector(5, "hello"); // 创建一个包含 5 个 "hello" 的 vector
7    std::vector<double> doubleVector{1.1, 2.2, 3.3}; // 创建一个包含 3 个 double 的 vector
6    std::vector<int> myVector;
7    myVector.push_back(10);
8    myVector.push_back(20);
9    myVector.push_back(30);
10
11    // 插入元素
12    myVector.insert(myVector.begin(), 5);
13    myVector.insert(myVector.begin() + 2, {3, 4, 5});
14
15    // 删除元素
16    myVector.pop_back();
17    myVector.erase(myVector.begin() + 2);
18
19    // 访问元素
20    int first = myVector.front();
21    int last = myVector.back();
22    int middle = myVector.at(2);
23
24    // 查找元素
25    auto it = std::find(myVector.begin(), myVector.end(), 10);
26    if (it != myVector.end()) {
27        std::cout << "Element found: " << *it << std::endl;
28    } else {
29        std::cout << "Element not found." << std::endl;
30    }
31
32    // 判断元素是否存在
33    bool contains = std::find(myVector.begin(), myVector.end(), 10) != myVector.end();
34
35    // 获取元素数量
36    size_t size = myVector.size();
37
38    // 清空容器
39    myVector.clear();
40
41    // 迭代器遍历
42    for (const auto& elem : myVector) {
43        std::cout << elem << " ";
44    }
45    std::cout << std::endl;
46
47    return 0;
48}// 遍历:
for (const auto& field : fields) {
16        std::cout << field << " ";
17    }push_back(item):vector后面添加一个元素item
pop_back():尾端删除数据
size():返回vector中所含元素的个数
clear():一键清空vector中的所有元素
insert(position, item):根据指定位置在vector中插入元素,v.insert(v.begin()+2,-1)
erase()
erase(position):删除指定位置的元素
erase(positionBegin, positionEnd):删除一个区间的元素
#include<vector>
using namespace std;vector<类型名> 变量名;vector<int> name;
vector<double> name;
vector<char> name;
vector<struct node> name;
vector<vector<int> > name;//注意:> >之间要加空格// vector数组就是一个一维数组,如果定义成vector数组的数组,那就是二维数组。
vector<int> array[SZIE]; //二维变长数组
// 在此,我送你一句话非常受用的话:低维是高维的地址。//访问
vecntor[i];
//修改
vector[i] = value;

2.3 map #include<map>


map<string, string> mp;
map<string, int> mp;
mao<int, node>find(key):返回键为key的映射的迭代器,用find函数来定位数据出现位置,数据不存在时,返回mp.end()
erase:
erase(it):删除迭代器对应的键和值
erase(key):根据映射的键删除键和值
erase(first, last):删除左闭右开区间迭代器对应的键和值
size():返回映射的对数
clear():返回映射的对数
insert():插入元素,插入时要构造键值对
empty():如果map为空,返回true,否则返回false
begin():返回指向map第一个元素的迭代器(地址)
end():返回指向map尾部的迭代器(最后一个元素的下一个地址)
rbegin():返回指向map最后一个元素的迭代器(地址)
rend():返回指向map第一个元素前面(上一个)的逆向迭代器(地址)count():查看元素是否存在,因为map中键是唯一的,所以存在返回1,不存在返回0
lower_bound():返回一个迭代器,指向键值>= key的第一个元素
upper_bound():返回一个迭代器,指向键值> key的第一个元素
//注意:
//找元素是否存在时,可以使用
①mp.find() ② mp.count() ③ mp[key]
但是第三种情况,如果不存在对应的key时,会自动创建一个键值对(产生一个额外的键值对空间)
所以为了不增加额外的空间负担,最好使用前两种方法//添加元素:mp["学习"] = "看书";
mp.insert(make_pair("vegetable", "蔬菜"));
mp.insert(pair<string, string>("fruit", "水果"));
//访问元素://迭代器访问
map<string, string>::iterator it;
for(it=mp.begin(); it!=mp.end(); it++) {cout << it->first << it->second << endl;
}//对指定单个元素访问
map<char, int>::iterator it = mp.find('a');
cout << it->first << " " << it->second << endl;

2.4 pair #include<utility>


//pair只含有两个元素,可以看作是只有两个元素的结构体//初始化定义
pair<string, int> p("111", 1); //带初始值
pair<string, int> p; //不带初始值//赋值
p = {"wang", 18};
p = make_pair("wang", 18);
p = pair<string, int>("wang", 18);pair<int, int> p[20];
//访问
for(int i=0; i<20; i++) {cout << p[i].first << " " << p[i].second << endl;
}

2.5 array

C++ 标准库中的容器类型:std::array -- C++11 引入的静态数组容器 ;

1. 固定大小 ;下标访问;
   - 支持 `begin()` 和 `end()` 方法来获取迭代器,用于遍历元素。
   - 支持 `empty()` 方法来判断数组是否为空。
   - 支持 `size()` 方法来获取数组的大小。

2.成员函数:
   - `fill(value)`:填充数组中的所有元素。 【所有赋相同值】  e.g.:  arr.fill(0);
   - `operator[]`:通过索引访问元素。
   - `front()`:获取第一个元素。
   - `back()`:获取最后一个元素。
   - `data()`:获取指向数组元素的指针。

3.可比较性 :
   - 支持比较操作符(`==`, `!=`, `<`, `<=`, `>`, `>=`),可以比较两个 `std::array` 是否相等或进行排序。

//创建array :std::array<int, 5> arr; // 创建一个大小为5的数组,所有元素初始化为默认值(0)std::array<int, 5> arr = {1, 2, 3, 4, 5}; // 使用初始值列表初始化std::array<int, 5> arr(5, 0); // 使用填充构造函数初始化所有元素为0//示例完整代码:
#include <iostream>
#include <array>int main() {// 创建一个大小为5的数组std::array<int, 5> arr = {1, 2, 3, 4, 5};// 访问元素std::cout <<   << arr.front()<< arr.back()  << std::endl; // 输出  : 1 5 // 遍历数组std::cout << "Elements: ";for (const auto &value : arr) {std::cout << value << " ";}std::cout << std::endl;

3-字符(串)常见处理:string/cctype

String /cctype 库: 【字符串处理 / 字符分类】

3.1 #include <string>

 【注意:不要定义string a =’1’//应该是”1”】

 
#include <string>
string 可以动态调整大小,不需要预先确定字符串的长度。
字符串操作(1)查找(2)替换(3)拼接(4)删除子串(5)比较e.g.:
#include <iostream>
#include <string>
int main() {// 创建std::string str = "Hello, World!";//访问by下标/at() :  char a= str[0]; char last = str.at(str.size() - 1); 	//拼接string str3 = str1 + str2;	//长度: size_t len = str.size();  int a=str.length(); 		// 查找子字符串size_t pos = str.find("World");// 默认从0下标开始找:返回其W的下标6;//【size_t是无符号整型 32位】int a = str.find("serach",6);//从指定位置开始找;// 使用 std::replace 替换 'a' 为 'c'replace(str.begin(), str.end(), 'a', 'c');// 替换子字符串str.replace(pos, 5, "1234a");//从pos下标的位置开始,替换5位的长度;// 删除字符str.erase(pos, 8); //从pos开始,删8位//string::substr() 或者自定义函数来分割字符串。string part = str.substr(7, 5); // 从7开始,算5位长度:"World"// 比较字符串string str3 = "Hello, Universe!";bool isEqual = str.compare(str3) ;return 0;// 查找 "World" 的前3个字符std::string str = "Hello, World!";const char* cStr = "World";size_t pos = str.find(cStr, 0, 3); // 查找 "Wor"/*
(6)string 类提供了成员函数来获取字符串的长度(如 size() 或 length()),
因此不需要使用空字符来标记字符串的结束。【char数组末尾是如'\0'】
*/
}
/*
1.	返回值 npos:如果找不到子字符串或字符,find() 会返回 string::npos【不是-1,一般是size_t的最大,32位除去符号位全为1】。
你需要检查返回值是否等于 npos 【一个已经在库里声明过的全局变量】来确定是否找到了匹配项。2.	性能考虑:find() 的时间复杂度通常为 O(n),其中 n 是主字符串的长度。在大型字符串中查找时,性能可能成为一个考虑因素。3.	多处查找:如果你需要查找所有出现的位置,可以结合循环使用 find()。每次查找后,从上次找到的位置之后开始下一次查找。
*/

3.2  #include <cctype>

功能:字符分类和转换。【判断 字母/数字/空白字符 / 大小写转换】;


//下面是一个使用 <cctype> 的示例:
#include <iostream>
#include <cctype>int main() {char ch = 'A';// 检查字符是否为字母bool isLetter = std::isalpha(ch);// 检查字符是否为数字bool isDigit = std::isdigit(ch);// 检查字符是否为空白字符bool isSpace = std::isspace(ch);// 检查字符是否为大写字母bool isUpper = std::isupper(ch);// 转换字符为小写char lowerCase = std::tolower(ch);// 转换字符为大写char upperCase = std::toupper(ch)return 0;
}


http://www.mrgr.cn/news/33622.html

相关文章:

  • Git - Think in Git
  • AlphaFold3中文安装教程
  • 【Xrdp联机Ubuntu20.04实用知识点补充】
  • LeetCode【0017】电话号码的字母组合
  • 论文阅读《BEVFormer v2》
  • 关于Dell r730xd 老服务器的阵列卡 配置系统盘RAID 1
  • error -- unsupported GNU version gcc later than 10 are not supported;(gcc、g++)
  • 条件编译及头文件包含
  • DAY78服务攻防-数据库安全RedisCouchDBH2database未授权访问CVE 漏洞
  • ModbusTCP通讯错误的排查
  • 数据处理与统计分析篇-day08-apply()自定义函数与分组操作
  • 【掘金量化使用技巧】用日线合成长周期k线
  • golang学习笔记8-运算符与输入
  • 使用Okhttp-服务器不支持缓存的解决办法
  • 百度智能云API调用
  • AI大模型基础概念
  • AD19基础应用技巧:交叉选择/跳转到器件/镜像粘贴/元器件矩形区域排列/选择过滤器/捕捉对象等设置
  • 插件化换肤的优缺点分别是什么
  • 【练习16】求最小公倍数
  • kindle云端同步
  • 项目扩展四:交换机和队列的特性完善【自动删除与队列独占的实现】
  • Java是怎么处理死锁的
  • hive-拉链表
  • LeetCode讲解篇之238. 除自身以外数组的乘积
  • torch模型量化方法总结
  • HarmonyOS元服务与卡片