今天是2024年1月28日,是我的十六岁生日,也是第一次信竞集训结束的日子。
十天的集训,收获很多,今天在这里进行一下总结,有故事,有板子,也有心得和创新。
一.心得
摘要:10天内学习了如下的PPT内容
1.c++基础语言(时空复杂度,语言基础)
2.STL和数据结构(3个函数,树,堆,单调队列,并查集)
3.基础算法(贪心,分治)选讲(装载、背包、渡河、区间,排序、染色)
4.Dp选讲(Dfs、背包(各种)、LIS、LCS)
5.基础图论(遍历、欧拉路径回路、拓扑、最短Floyd、Dijkstra、spfa、tarjan)
6.基础数论(素数定理、筛法、整除、同余:gcd||exgcd、逆元、CRT、拓展CRT、欧拉函数、莫比乌斯函数、Lucas定理)
二.板子(各种)
1.时间复杂度的判断:

2.变量范围:
3.运算符:
4.输入输出:
5.vector:
头文件:<vector> vector支持随机存取,甚至你完全可以把它视为一个元素个数可以变化的数组。
Vector<int> a 定义一个存放int的vector a
v.at(i):返回索引i所标识的元素。对i会进行越界检查。
v[i]:返回索引i所标识的元素,和数组用法几乎完全相同。对i不进行越界检查。
v.front():返回第一个元素。不检查第一个元素是否存在。
v.back():返回最后一个元素。不检查最后一个元素是否存在。
v.insert(pos, e):在pos位置插入元素e的副本,并返回新元素位置。
v.insert(pos, n, e):在pos位置插入n个元素e的副本。
v.insert(pos, begin, end):在pos位置插入区间[begin, end)内所有元素的副本。 注意,以上三种操作涉及大量元素的移动,可能会严重影响效率。
v.push_back(e):在尾部添加一个元素e的副本。
v.reserve(n):扩大容量为n。
6.set:
Set<int> s 创建一个储存int的set s
begin() 返回set容器的第一个元素的迭代器
end() 返回set容器的最后一个元素的迭代器
clear() 删除set容器中的所有的元素
empty() 判断set容器是否为空
size() 返回当前set容器中的元素个数
erase(iterator) ,删除迭代器iterator指向的值
erase(first,second),删除迭代器first和second之间的值
erase(key_value),删除键值key_value的值
count() 用来查找set中某个某个键值出现的次数。因为一个键值在set只可能出现0或1次,这样就变成了判断某一键值是否在set出现过了。
find() ,返回给定值的迭代器,如果没找到则返回end()。
insert(key_value); 将key_value插入到set中
lower_bound(key_value) ,返回第一个大于等于key_value的定位器
upper_bound(key_value),返回最后一个大于key_value的定位器
7.迭代器
set::iterator it; //迭代器的创建
it=s.find(5) ; //迭代器的定向
it++; //迭代器移向容器下一个元素
printf(”%d\n”,*it); //输出迭代器指向的值
for(it=s.begin();it!=s.end();it++) //容器的遍历 Printf(“%d “,*it);
8.map
map<int,string> m 建立一个key值为int,value值为string的map m
m.at(3)或m[3]:返回一个引用,指向键为3时的对应值。注意,它和数组下标完全不是一回事儿!
如果元素不存在,map会自动建立这个元素。
m.count(3):返回s中键为3的具体数目。但对于map来说,返回值不是0就是1。
m.find(3):返回指向键为3的元素的迭代器。如果不存在,则返回m.end()。
m.empty():判断映射是否为空映射。
m.size():返回映射的元素数量。
m.insert(pair):将元素插入到set中。pair的first是键,second是值。
可以定义一个pair:pair <int, string> p(10, "Hello"); 也可以用make_pair(<utility>)建立一个pair:make_pair(10, "Hello");
m.insert(begin, end):将区间[begin, end)中的值插入到s中。该区间应该是map类型的。 m.erase(e):将键为e的元素删除。返回值为被删除的e的数量(对于multimap来说,被删除的可能不止一个元素)。
m.erase(pos):将pos处的元素删除。
m.erase(begin, end):将[begin, end)处的元素删除。
9.二叉树的遍历
//二叉树的先序、中序、后续遍历
void dfs(int x)
{
printf("%d\n",x);
if(ls[x])
dfs(ls[x]);
if(rs[x])
dfs(rs[x]);
}
void dfs(int x)
{
if(ls[x])
dfs(ls[x]);
printf("%d\n",x);
if(rs[x])
dfs(rs[x]);
}
void dfs(int x)
{
if(ls[x])
dfs(ls[x]);
if(rs[x])
dfs(rs[x]);
printf("%d\n",x);
}
//二叉树的层次遍历
void bfs(int x)
{
q[top ++] = x;
for(int i = 1;i <= top;i ++)
{
int now = q[i];
printf("%d\n",now);
if(ls[now])
q[top ++] = ls[now];
if(rs[now])
q[top ++] = rs[now];
}
}
10.在堆中插入元素,求最大值
//堆,插入元素
void insert(int x)
{
int now = n ++;
heap[now] = x;
while(now != 1 && head[now] > heap[now] / 2)
swap(head[now],head[now / 2]);
now /= 2;
}
//求最大值
int top()
{
return head[1];
}
删除最大值
//删除最大值
void del()
{
heap[n --] = heap[1];
int now = 1;
while(heap[now] < max(heap[now * 2],head[now * 2 + 1]))
{
if(heap[now] < head[now * 2])
swap(head[now],heap[now * 2]);
now *= 2;
if(heap[now] < head[now * 2 + 1])
swap(head[now],heap[now * 2 + 1]);
now = now * 2 + 1;
}
return;
}
11.单调队列
priority_queue <int,vector<int>,less<int> > q; //定义大根堆q (可简化为priority_queue <int> q;)
priority_queue <int,vector<int>,greater<int> > q; //定义小根堆q
top() 访问队头元素
empty() 队列是否为空
size() 返回队列内元素个数
push(x) 插入元素x
pop() 弹出队头元素
12.单调队列输出最大值
//单调队列输出最大值
for(int i = 1;i <= n;i ++)
{
if(q[head] <= i - m)
head ++;
while(head <= tail && a[q[tail]] < a[i])
tail --;
q[tail ++] = i;
ans[i] = a[q[head]];
}
for(int i = m;i <= n;i ++)
{
cout << ans[i];
}
13.并查集的查询和合并
//并查集的查询和合并
int find(int x)
{
return fa[x] = x == fa[x] ? x : fa[x] = find(fa[x]);
}
void marge(int x,int y)
{
int u == find(x),v = find(y);
if(u == v)
return;
if(rk[u] > rk[v])
swap(u,v);
fa[u] = v;
rk[v] += rk[u] == rk[v];
}
14.贪心分治
重在思想(bushi)
好像真的没有什么板子
15.Dp思想
关键词:状态,转移
动态规划的两步:
1.设计状态
2.构建状态转移方程
数字金字塔
//数字金字塔
for(int i = n;i;i --)
{
for(int j = 1;j <= i;j ++)
{
if(i == n)
f[i][j] = a[i][j];
else
f[i][j] = a[i][j] + max(f[i + 1][j],f[i + 1][j + 1]);
}
}
//O(n^2)
搜索的对比
//搜索的对比
int dfs(int x,int y)
{
if(x == n)
return a[x][y];
return a[x][y] + max(dfs(x + 1,y),dfs(x + 1,y + 1));
}
int dfs(int x,int y)
{
if(x == n)
return a[x][y];
if(vis[x][y])
return f[x][y];
vis[x][y] = 1;
return f[x][y] = a[x][y] + max(dfs(x + 1,y + 1));
}
01背包
//01背包
for(int i = 1;i <= n;i ++)
{
for(int j = m;i >= w[i];j --)
{
dp[j] = max(dp[j],dp[j - w[i]] + v[i]);
}
}
完全背包
//完全背包
for(int i = 1;i <= n;i ++)
{
for(int j = w[i];i <= m;j ++)
{
dp[j] = max(dp[j],dp[j - w[i]] + v[i]);
}
}
背包计数
//背包计数
for(int i = 1;i <= n;i ++)
{
for(int j = m;j >= w[i];j --)
{
dp[j] += dp[j - w[i]];
}
}
多重背包
//多重背包
for(int i = 1;i <= n1;i ++)
{
cin >> a >> b >> c;
for(int k = 1;k <= c;k <<= 1)
{
v[u ++] = k * a;
w[u] = k * b;
c -= k;
}
if(c)
v[++u] = a * c;
w[u] = b * c;
}
16.基础图论
之前写过了
17.基础数论
素数定理

算数基本定理

朴素筛、埃氏筛、欧拉筛
//朴素筛、埃氏筛、欧拉筛
for(int i = 1;i <= sqrt(n);i ++)
{
if(n % i == 0)
p[n] = 0;
}
p[n] = 1;
//O(sqrt(n))
for(int i = 2;i <= n;i ++)
p[i] = 1;
for(int i = 2;i <= n;i ++)
{
if(p[i])
for(int j = i * 2;j <= n;j += i)
p[j] = 0;
}
//O(nloglogn)
for(int i = 2;i <= n;i ++)
{
if(!vis[i])
p[pn ++] = i;
for(int j = 1;j * p[j] <= n;j ++)
{
vis[i * p[j]] = 1;
if(i % p[j] == 0)
break;
}
}
//O(n)
整除定理
a|b, b|c −> a|c
a|b, a|c −> a|s×b+t×c
a|b, b|a −>|a|=|b|

gcd
//gcd
int gcd(int x,int y)
{
return y == 0 ? x : gcd(y,x % y);
}
//O(log(a + b))
同余理论
整数 a,b 满足 m|a-b ,那么称 a 和 b 在模 m 下同余,记作 a ≡b (mod m)
对于 a ≡b (mod m) ,若 d|m ,则 a ≡b (mod d)
对于 a ≡b (mod m) ,若 d|m,d|a,d|b ,则 a/d ≡b/d (mod m/d)
对于 a ≡b (mod m) ,有 gcd(a,m)=gcd(b,m)
对于质数 m_1 和 m_2 ,若 gcd(m_1,m_2)=1 ,则 {m_2x_1+m_1x_2 mod m_1m_2|x_1,x_2∈ ℤ}= {x mod m_1m_2|x∈ ℤ}
exgcd
//exgcd
void exgcd(int a,int b,int &g,int &x,int &y)
{
if(!b)
x = 1,y = 0,g = a;
else
{
exgcd(b,a % b,g,y,x);
y -= x * (a / b);
}
}
//O(log(a + b))
同余原则+乘法逆元+两个定理
ax+by=gcd(a,b)->a(x*(z/gcd(a,b)))+b(y*(z/gcd(a,b)))=z
可以看出有解的充要条件是gcd(a,b)|z
对于正整数a,若存在s使as=1(mod m)
记 s 是 a 在模 m 下的逆元,即 s=a^−1 (mod m)
a存在逆元的充要条件:(a,m)=1
这就是伟大的————费马小定理和威尔逊定理
费马小定理:若 p 是质数,则对于任意整数 a 有 a^p=a (mod p)
威尔逊定理:若 p 是质数,则有 (p−1)!=−1 (mod p)
//线性逆元
//k*i+r=0(mod m)
//i^(-1)=-kr(mod m)
inv[1] = 1;
for(int i = 2;i <= p;i ++)
inv[i] = (p - p / i) * inv[p % i] % p;
//O(n)
CRT

使用exgcd进行合并
欧拉函数

性质:
1.积性函数! (什么是积性函数?) 积性函数:若对任意互质的两个数m和n有f(m*n)=f(m)*f(n),则 f(x)是积性函数。若对任意两个数(不要求互质)都有 f(m*n)=f(m)*f(n),则f(x)是完全积性函数。
2.对质数p, φ(p)=p-1。
3. ⼩于n的数中,与n互质的数之和为φ(n)*n/2 (n>1)。
4. n的所有因数的欧拉函数之和等于n
线性筛带来的欧拉函数
//线性筛欧拉函数
for(int i = 2;i <= n;i ++)
{
if(!vis[i])
p[pn ++] = i;
phi[i] = i - 1;
for(int j = 1;i * p[j] <= n;j ++)
{
vis[i * p[j]] = 1;
if(i % p[j] == 0)
{
phi[i * p[j]] = phi[i] * p[j];
break;
}
phi[i * p[j]] = phi[i] * phi[p[j]];
}
}
莫比乌斯函数

//莫比乌斯函数
mu[1] = 1;
for(int i = 2;i <= n;i ++)
{
if(!vis[i])
p[pn ++] = i;
phi[i] = -1;
for(int j = 1;i * p[j] <= n;j ++)
{
vis[i * p[j]] = 1;
if(i % p[j] == 0)
{
mu[i * p[j]] = 0;
break;
}
phi[i * p[j]] = -phi[i];
}
}
欧拉定理(降幂原则)
欧拉定理:若 m 是正整数,gcd(a,m)=1 ,则有 a^φ(m)=1 (mod m)
可以看出费马小定理是欧拉定理的特殊情况
降幂公式:若 m,n 是正整数,n>φ(m) ,则有 a^n=a^n mod φ(m) + φ(m) (mod m)
Lucas定理
给定质数 p ,求 (n¦k) % p 。 (n¦k)=(n/p¦k/p)(n%p¦k%p)
相当于把 n 和 k 拆成 p 进制数,然后每一位对应求组合数,最后再乘起来
快读
//快读
int read()
{
int x = 0,f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')
f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9')
x = x * 10 + ch - '0',ch = getchar();
return x * f;
}
快写
//快写
void write(int x)
{
if(x < 0)
putchar('-'),x = -x;
if(x > 9)
write(x / 10);
putchar(x % 10 + '0');
return;
}
三.创新
1.廿四筛似乎还未过时??
2.Tarjan新证明,至少新开了一个思路
四.回首
第一次OI集训,十天,说实话,很烧脑,整天都处于连轴转的状态,好在后期讲的图论数论我比较喜欢,如果是Dp或STL的话可能直接就爆零了(bushi)
第一天的基础知识对于我是一个很舒服的起点,唤醒了我可能一个半月没进行OI的感觉。第二天的STL,个人认为是状态最不好的一天,原本基础是不好的,做题还有回家还没有订正总结,感觉一知半解吧,它直接导致我后面几天思路就算快了也并没有很快AC,未来的3周STL优先级应该是最高的,毕竟去了HL不能丢廿四的脸!!!随后的分治、贪心,初中和秋季学过,一切正常,但是回家复习时发现排序也是我的一个短板!!要及时订正!!后来的Dp(背包),很难很难,尤其是区间 DP 和状压 DP,这就导致前面的01背包的自信跌没了??也是一个重点啊!!
个人向订正,加强方向:
STL重点中的重点,这是一个承前启后的知识!!!
Dp,顺带着全看了吧,反正十分重要!!!
排序,认真分析KHIN给过的代码!!
以上是问题,但是呢,GG说过,要鼓励自己,所以我也简单说说十天中有的和要发扬的优点:
1.准时早起,最自豪的一点!!基本每天都是前三,没有自吹自擂成分啊,家就是近(doge)
2.能有定力
3.自己编样例
4.提高了分析在做题过程中的比例,而不是敲代码
同样,我也有除编程之外的问题:
1.中午休息后不能很快进入状态
2.只注意程序的设计,不注重调试
3.求助次数太多了,缺少足够的自己思考
4.有时不求甚解(尤其是不喜欢的知识,记住:知识没有喜不喜欢,只有认不认真!!!)
五.故事
十天的精彩太多太多了
大家第一天的睡姿(doge)
OI男团特色叫醒服务(@Nihachu)
@类人群星闪耀时的小~~乐器
OI嘲哳合唱团
思韵噪音民乐团
明目张胆的跑饭(甚至全程第一人称录像)
寻找解封的教室
去拜访其他学科竞赛(当然也是在他们休息的时候)
在高三学哥学姐们面前公然看手机
特色桌面
OI的迁徙
1300多分钟的录屏
我写这些,只是不希望忘记他们,毕竟,在那烧脑的十天里,因为这些事情,我们更加热爱OI
六.感动
十天的集训,大家真正熟识起来,个人认为是大家开始互相叫网名(doge),每个人也都不惧提问,乐于奉献,在此感谢(排名不分先后):
A2391833679
Snowycat1234
Liuooo
Feng_xiaomo
Qwehhh
Wrose
类人群星闪耀时
潇寞
Viki617
Nihachu
耐心解答、指出我的问题。
不知是不是冥冥中的安排,今天,最后一天集训,是我的生日,一早便收到了大家的祝福,后来更是共同为我买了蛋糕。午风中,我面对大家的祝福,许下了我自己的愿望,虽然我不会直接告诉你们,请不用担心,一定有对你们的祝福!
七.结语
在这里写下可以告诉你们的祝福吧:
祝大家:
冒泡排序,选择排序,插入排序,快速排序,堆排序,归并排序,希尔排序,桶排序,基数排序新年帮您排忧解难。
有向图,无向图,有环图,无环图,完全图,稠密图,稀疏图,拓扑图祝您新年宏图大展。
最长路,最短路,单源路径,所有节点对路径祝您新年路路通畅。
二叉树,红黑树,van Emde Boas树,最小生成树祝您新年好运枝繁叶茂。
最大流,网络流,标准输入流,标准输出流,文件输入流,文件输出流祝您新年顺顺流流。
线性动规,区间动规,坐标动规,背包动规,树型动归为您的新年规划精彩。
散列表,哈希表,邻接表,双向链表,循环链表帮您在新年表达喜悦。
O(1), O(log n), O(n), O(nlog n), O(n^2), O(n^3), O(2^n), O(n!)祝大家新年渐进步步高。
区间DP,树形DP,数位DP,概率DP,分数规划,线性规划,教你规划人生;
平衡树,划分树,归并树,k-d树,主席树,树套树,替罪羊树,让你运筹帷幄。
BFS,DFS,A*,记忆化,使你在大千世界里寻找难觅幸福;
Bellman-Ford,Johnson,Floyd,Dijkstra,让你在匆匆人生中走上成功捷径。
高斯消元,约当消元,帮你拨云见雾;
AC自动机,后缀自动机,有限状态自动机,助您理清头绪。
RMQ,LCA,让您节节高升。
祝大家新春快乐,AK Forever,24OI-24k24k,曜宁学长在PKU学业顺遂,大家共同奔赴下个赛季,制造属于我们的辉煌。也祝Merlin·Aquarius·Mark·Uranus·Lee(李墨林)在未来的学习,OI都讲述属于自己的故事。祝我所有的OI和非OI的朋友走向无数地方和无尽岁月,搭着肩环游无法遗忘的光辉世界。奋斗三周,HL再见!
我和我最后的倔强
握紧双手绝对不放
下一站是不是天堂
就算失望 不能绝望
我和我骄傲的倔强
我在风中大声地唱
这一次为自己疯狂
就这一次 我和我的倔强
@Merlin Lee
博主在2024年1月28日结束第一次信竞集训,进行总结。10天学习了C++基础、STL、基础算法、图论、数论等知识,还分享了各种代码模板。同时提到创新点,回顾集训问题与优点,讲述集训故事与感动,最后送上新年祝福。
201

被折叠的 条评论
为什么被折叠?



