elric
23 次阅读
约 4 分钟 · 1092 字
ACM算法比赛做题小技巧笔记
C++
#include <iostream>#include <algorithm> int main() {    int array[] = {1, 2, 3, 4, 5};     if (std::is_sorted(array, array + 5)) {        std::cout << "数组已按升序排列" << std::endl;    } else {        std::cout << "数组未按升序排列" << std::endl;    }     return 0;} 

加法(a+b)与异或(a^b)的奇偶性相同

一直将一个数相减,就是指相除或求余

C++
// 从第零个开始执行,但第零个默认执行,其他的要根据第二个判断来判断if (!i || /*条件2*/ )

tuple 与 pair

加上一个负数,肯定比原数小,

C++
// 如果sum<0:    sum=0,sum+=a[i] > sum+=a[i]
C++
for(int i=0;i<n;i++){   cin>>x>>y;// 普通左边,横坐标向右,竖坐标向下   a[x-y+MAXNN]++;// 左下到右上的对角线坐标   b[x+y-1]++;// 左上到右下的对角线坐标}// MAXNN为这个正方形网格的边长,记得要从1开始,对角线数组的长度>2*边长+10 比较好

打比赛时要关了 copilot 他在干扰思路方面远远大于补充的作用,学习等时候再打开(副驾驶只是辅助(学习)的,但要是直接去开车的话,有个人在旁边哔哔哔,可能会扰乱思路)

有时候,要假设某种最低限度的情况是否成立,如果成立,则也成立,这也是一种贪心呀

还有分开一个数的时候,不仅仅只有二分,还有平均分。平均分分的个数有时候要小于二分的 (前一个数要小于后一个数(任意分两瓣的犯法))

还有,如果一个题一直错,要想想是不是自己的思路错了,而不是一直犟着同一种思路不放

数组是先行后列 a[i][j] ,i 表示行,j 表示列

C++
// 行是三行排,之前把列与行的定义搞反了// 反正记住二维数组是先竖着多少个,然后横着多少个int main(){	int a[3][4] ={		{1,2,3,4},		{3,4,5,5},		{67,3,9,6}	};	for(int i=0;i<3;i++)	{		for(int j=0;j<4;j++)			cout<<a[i][j]<<' ';		cout<<endl;	}	return 0;}// 输出:1 2 3 43 4 5 567 3 9 6

VSCode 中可以通过“调试”中的“监视”中,添加全局变量名称来查看它(数组也写变量名即可)

模运算性质

(a+b)%n = (a%n + b%n)%n

``(ab)%n = ((a%n)(b%n))%n`

逆元

什么是逆元

逆元是数学中的一个概念,主要在代数和数论中使用。在模运算中,给定一个整数 a 和一个正整数 n,如果存在一个整数 b,使得 (a*b) mod n = 1,那么我们就说 b 是 a 模 n 的乘法逆元

如:

ParseError: KaTeX parse error: Undefined control sequence: \* at position 13: \begin{align\̲*̲}\label{2} & ∵(…

使用 Dev-C++查看 vector 数组中的变量值

C++
vector<int> a[100000];// 就是邻接表辣~//它声明了一个名为 a 的数组,数组中有 100,000 个元素,每个元素都是一个 vector<int> 类型的对象

lcm 与 gcd 算法的两个数输入是没有顺序的

如何在 DevC++中使用 g++11

C++
int match[MAXN];// 下面的是同一个意思memset(match, -1, sizeof(match)); fill(match, match + MAXN, -1);fill_n(match, MAXN, -1);

对于std::vector,它的迭代器支持以下几种操作:

  1. ++和--:这两个操作分别用于将迭代器向前或向后移动一个位置。例如,如果it是一个迭代器,那么++it会将it向前移动一个位置,--it会将it向后移动一个位置。
  2. +和-:这两个操作用于将迭代器向前或向后移动多个位置。例如,it + n会返回一个新的迭代器,这个迭代器指向it当前指向的元素后面的第 n 个元素。同样,it - n会返回一个新的迭代器,这个迭代器指向it当前指向的元素前面的第 n 个元素。
  3. *:这个操作用于获取迭代器当前指向的元素的引用。例如,*it就是it当前指向的元素。
  4. ==和!=:这两个操作用于比较两个迭代器是否相等。如果两个迭代器指向同一个元素,那么它们相等;否则,它们不相等

若要对负数取模,都要先+mod,再%mod

mp.erase(s);和mp[t].clear()有什么区别

mp.erase(s);和mp[t].clear();这两个操作在 C++中的std::map上有着不同的含义和效果。

mp.erase(s);是用来删除键为s的元素。如果mp中存在键为s的元素,那么这个元素会被删除,mp的大小会减 1。如果mp中不存在键为s的元素,那么这个操作不会有任何效果。

C++
std::map<int, int> mp;mp[1] = 100;mp[2] = 200;mp.erase(1);  // 删除键为1的元素

mp[t].clear();这个操作首先会找到键为t的元素,然后调用这个元素的clear方法。这个操作通常用于std::map的值是容器(如std::vector,std::string等)的情况。如果mp中不存在键为t的元素,那么会插入一个键为t的元素,然后调用这个新插入元素的clear方法。

C++
std::map<int, std::vector<int>> mp;mp[1] = {100, 200, 300};mp[1].clear();  // 清空键为1的元素的值

如果mp的值不是容器,那么mp[t].clear();这个操作可能会导致编译错误,因为不是所有的类型都有clear方法。

最大公因数又叫最大公约数,这样就好理解了

c++使用 vector 创建二维数组并指定大小

二维都变长的二维容器数组

1、在 C++中,可以这样初始化一个二维 vector 数组并指定大小:

cppvector<vector<int>> vec(3, vector<int>(4));

这个代码会创建一个 3 行 4 列的二维 vector 数组,每个元素初始化为 0:vec =
[0 0 0 0]
[0 0 0 0]
[0 0 0 0]

2、你也可以在初始化时指定每个元素的值:

cppvector<vector<int>> vec(3, vector<int>(4, 1));

这个会创建一个 3 行 4 列的二维 vector,每个元素初始化为 1:vec =
[1 1 1 1]
[1 1 1 1]
[1 1 1 1]

3、如果你想指定每个 vector 的大小,并手动初始化每个元素,可以这样写:

cppvector<vector<int>> vec;vec.resize(3);        // 3行 vec[0].resize(4);     // 第一行4列vec[0] = {1, 2, 3, 4}; vec[1].resize(2);     // 第二行2列vec[1] = {5, 6}; vec[2].resize(3);     // 第三行3列vec[2] = {7, 8, 9};

这个会创建:

vec =
[1 2 3 4]
[5 6 0 0]
[7 8 9 0]

总结

所以总结一下,初始化一个二维 vector 数组并指定大小的方法有:

  1. vector<vector> vec(行数, vector(列数));
  2. vector<vector> vec(行数, vector(列数, 初始值));
  3. vector<vector> vec; vec.resize(行数); vec[i].resize(列数); vec[i] = {值};

一维长度固定,二维长度可变的二维容器数组

vector v[n] n 为第一维的长度

// 初始化一个一维长度为3的vectorvector<vector<int>> vec(3); // 为每个一维vector初始化不同长度vec[0] = vector<int>(5);vec[1] = vector<int>(10);vec[2] = vector<int>(2); // 打印vecfor (int i = 0; i < vec.size(); ++i) {  for(int j = 0; j < vec[i].size(); ++j) {    cout << vec[i][j] << " ";  }  cout << endl;}

补充:一维容器的初始化

vector<int> v(n)`表示声明一个容器v,并给他预定存储空间。每一个单元初始化为0,因此,`vector<int> v(n)`也等同于`vector<int> v(n, 0)`。当然,如果想要初始化为其他值,也可以改为`vector<int> v(n, val)

vector v(5);
cout << v.size() << endl;
for (int i = 0; i < v.size(); i++) {
cout << v[i] << " ";
}
cout << endl;
vector w(5, -1);
for (int i = 0; i < w.size(); i++) {
cout << w[i] << " ";
}

获取一个数组中最大值

C++
int maxsize = *max_element(a.begin(), a.end());=============================================================std::vector<int> v = {1, 2, 3, 4, 5};auto max_iter = std::max_element(v.begin(), v.end());int max_value = *max_iter;std::cout << max_value << std::endl;  // 输出:5

gcd(a, b, c) = gcd(gcd(a, b), c)

next_permutation 是 C++ 标准库中的一个函数,它用于重新排列范围内的元素,以生成下一个字典序更大的排列。如果能够生成这样的排列,则函数返回 true;如果这已经是最大的排列(即没有更大的排列),则函数重新排列为最小的排列(字典序最小)并返回 false。

这个函数通常用于生成给定序列的所有排列,或者在需要按字典序处理序列的情况下找到下一个排列。

函数原型如下:

C++
bool next_permutation(BidirectionalIterator first, BidirectionalIterator last);

这里,first 和 last 是双向迭代器,分别指向序列的开始和结束。

使用 next_permutation 的一个简单示例:

C++
#include <algorithm>#include <vector>#include <iostream> int main() {    std::vector<int> vec = {1, 2, 3};     do {        for (int num : vec) {            std::cout << num << " ";        }        std::cout << "\n";    } while (std::next_permutation(vec.begin(), vec.end()));     return 0;}

这段代码会打印出向量 {1, 2, 3} 的所有排列:

1 2 31 3 22 1 32 3 13 1 23 2 1

next_permutation "c:/TDM-GCC-64/lib/gcc/x86_64-w64-mingw32/10.3.0/include/c++/bits/stl_algo.h") 通过比较和交换元素来工作,不需要额外的存储空间。


总结反思:

上分技巧

1400以下

  • 在5~10分钟之内可以快速的编写 直接的模拟

  • 在5~10分钟之内可以快速的编写 暴力思路

  • 在纸上或大脑中将问题分为某些情况 (n=2,n=3,n>=4)

  • 一道题15分钟都找不到解决方案就去换下一题

1400~1900

  • acwing算法基础课的内容就已经足够到1900分cf了(大一上的知识点)

  • 想上高分主要是要多刷对应分值的题

    • 每一阶段(每200分)能做出来100题,就说明已经完全掌握了它

1900~2200

  • 线段树及以上的中阶算法可以让你从1900上到2200分

  • 这时想要上分就要多去打虚拟赛

  • 这时还要多备用一些算法模板库,越全越好(要自己写的)

2200~2400

  • 要在div1比赛中成功解决只有不到100人才能解决的难题

  • 最少要解决4000道题

其他

  • 每周最少思考一次许多较为困难的问题

  • 训练赛咋样无所谓,重要是做题

    • 不关心在比赛中的评级

    心理问题是竞争对手竞争中最常见的问题之一。即使对我来说,直到2个月前,因为害怕在一场比赛中降低100+评分,我在超过9个月的时间里不能参加任何CF评分比赛。此外,有几个比赛,我甚至不能阅读后面的问题,因为我不能解决更容易的问题,失去了我的冷静。

    • 不关心错误

    错误也是一个很好的学习机会,没有一个人不会犯任何错误。甚至连游
    客在AtCoder世界巡回赛决赛中也犯了一个错误。

  • 总之,不要在比赛中有太多的压力,玩得开心!

如何练习

  • 每天2~3h的虚拟赛

  • 每周一次,从2200~2800中选择5个问题,并在2~4h中解决

评论区

分享你的想法,与大家交流讨论

Twikoo 加载失败

Twikoo 脚本加载失败