集训总结(新春前的诗)(Final七步曲版)

博主在2024年1月28日结束第一次信竞集训,进行总结。10天学习了C++基础、STL、基础算法、图论、数论等知识,还分享了各种代码模板。同时提到创新点,回顾集训问题与优点,讲述集训故事与感动,最后送上新年祝福。

今天是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.基础图论

之前写过了

图论的总结(知足)(板子)-CSDN博客

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.廿四筛似乎还未过时??

我似乎发现了一种很新的素数筛法-CSDN博客

2.Tarjan新证明,至少新开了一个思路

Tarjan的证明(bushi)-CSDN博客

四.回首

第一次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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值