ACM之旅
ACM算法之旅
辉小歌
九局下半转啊转,我把帽子反戴,还在期待逆转。
展开
-
刷算法题浅谈
随便谈一谈原创 2023-02-13 11:50:05 · 523 阅读 · 0 评论 -
简易的算法板子
#include<bits/stdc++.h>using namespace std;/*#pragma GCC optimize(2)exp(n) e的n次方const double e=2.7182818284590452353602874713527;priority_queue<int,vector<int>,greater<int>>q; std::ios::sync_with_stdio(false);std::cin.tie(n原创 2022-04-13 21:22:35 · 484 阅读 · 0 评论 -
ACM入门之【读入、输出优化】
本文主要是基于oiwiki的做的总结,未来也会做一系列的相关文章。如果想继续看的话可以关注专栏。做这个专栏的目的是因为自己最近开始系统的再打一下基础。于是想写一个专栏便于喜爱ACM的初学者入门。目录为啥要读入、输出优化优化方法一: 关闭同步/解除绑定优化方法二: 快读、快写各种情况下的时间对比总的模板为啥要读入、输出优化其实,读入、输出优化的目的就是防止我们因为读入、输出的问题使我们的程序TLE。于是我们需要读入、输出优化。来减少我们的运行时间,达到AC题目的目的。那么对于每道题我们是否需要.原创 2021-12-04 15:02:00 · 2528 阅读 · 4 评论 -
ACM之【文件操作】
文件操作在竞赛中用于调试是十分舒服的标准模板:#include<bits/stdc++.h>using namespace std;int main(void){ freopen("data.in","r",stdin); //data.in就是读取文件的文件名,要和可执行文件放在同一目录下 freopen("put.out","w",stdout); //put.out就是输出文件的文件名,要和可执行文件放在同一目录下 /* 编程代码部分 */ /原创 2022-02-28 23:27:16 · 320 阅读 · 0 评论 -
ACM之【对拍】
首先,我们要了解何为对拍。对拍其实就是我们弄一个随机的种子让其生成很多的数据,让两份程序跑,看跑出来的答案是不是都是一样的。对拍经常使用的场景:平时训练中,我们写的程序有问题但是不知道是哪些数据导致错误的。可以从网上复制一份别人正确的代码。用种子生成数据,将我们自己的代码和别人的代码对拍找到错误的数据点。比赛中可以用对拍检测代码的正确性。可以自己写一个暴力的代码和自己优化后的代码对拍,看优化后的代码是不是正确的。随机种子的生成,根据问题也是对应很多不同的模板。这些可以自己写一个,或者网上找人原创 2021-10-01 22:29:21 · 1166 阅读 · 0 评论 -
ACM之【运算符重载结合STL】
运算符重载在算法比赛中还是特别重要的。我之前个人是喜欢写一个比较函数,这样很方便,但是只是适用于sort。故这里举一个运算符重载的例子,当再次需要运算符重载的时候可以直接参考套用。例子:给出 𝑛 个学生的姓名和分数,按分数降序排序,分数相同者按姓名字典序升序排序,输出排名最靠前的人的姓名和分数。#include<bits/stdc++.h>using namespace std;struct student{ string name; int score;};st原创 2022-03-02 16:49:59 · 198 阅读 · 0 评论 -
ACM入门之【离散化】
离散化:就是说一些数据的数据范围很大,但是数据的个数很少。此时我们可以离散化一下。将其对应的数字映射到一个较小的下标。离散化的两种方法:排序,去重用哈希表来离散化//好处是有序的vector<int>a;sort(a.begin(),a.end());//排序a.erase(unique(a.begin(),a.end()),a.end());//去重map<int,int>mp;int idx;int get(int x){ if(mp.count原创 2022-03-10 16:11:32 · 385 阅读 · 0 评论 -
ACM入门之【高精度】
高精度加法模板:vector<int>A,B;string a,b;vector<int> add(vector<int> A,vector<int> B){ vector<int>C; int t=0; for(int i=0;i<A.size()||i<B.size();i++) { if(i<A.size()) t+=A[i]; if(i<B.si原创 2022-03-10 14:26:50 · 310 阅读 · 0 评论 -
ACM入门之【前缀和】
前缀和在ACM中算是一个简单易学且十分重要的一个算法。前缀和的种类:一维前缀和二维前缀和高维前缀和(比较少见)树上前缀和对于一维前缀和,它可以解决O(1)的时间复杂度来获取某一区间的和。对于二维前缀和,它可以解决O(1)的时间复杂度来获取某一矩阵的和。前缀和的弊端,即前缀和数组构造后不能再次的修改,否则还得再次构建,时间复杂度会大幅度的上升。一维前缀和模板:const int N=1e5+10;int a[N],s[N],n;void init()//构造前缀和 { fo.原创 2022-03-02 22:49:37 · 362 阅读 · 0 评论 -
ACM入门之【差分】
简言之:差分可以O(1)的给一段区间或矩阵加减相等的值差分的分类:一维差分二维差分树上差分点差分边差分原创 2022-03-04 14:23:12 · 335 阅读 · 0 评论 -
ACM入门之【ST表/RMQ】
st表的作用是可以快速的得到区间内的一个最值(最大值或最小值),不过它是静态的,即一旦初始化不能修改。ST表它可以做到O(nlogn)预处理,O(1)查询最值。原创 2022-03-04 14:46:44 · 243 阅读 · 0 评论 -
ACM入门之【二分】
二分分为:整数二分浮点数二分二分可以解决的问题:如果它左边的区间不满足条件,右边区间都满足条件。那么就可以用二分O(log2n)的时间复杂度解决问题。模板bool check(int x) {/* ... */} // 检查x是否满足某种性质// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:int bsearch_1(int l, int r){ while (l < r) { int mid = l + r >原创 2022-03-09 19:27:12 · 232 阅读 · 0 评论 -
ACM入门之【哈希】
哈希在竞赛中也是一个很常用,且非常厉害的一个算法。哈希的主要思想就是把一个东西转换成一个大整数,这样比较两个东西是否相等的就只要比较两个整数是否相等就行了,比较的时间复杂度是O(1)的。举一个比较常见的例子:比较俩字符串是否相等,我们可以将字符串变成一个值,然后直接比较这俩字符串的哈希值就行了。可能你会有疑问?在c++中string 不是可以直接就比较了么? 为啥还要用哈希呢?假如人家问的是俩矩阵是否相等呢?假如人家问这个矩阵是否在一个大矩阵中出现过呢?那么如何存矩阵呢?我们就可以用二维哈希.原创 2022-03-10 10:21:21 · 779 阅读 · 0 评论 -
ACM入门之【单调栈】
何为单调栈,顾名思义,单调栈即满足单调性的栈结构。单调栈解决的问题:可以找到对于当前位置左边(或右边)最近的大于(或小于)它的值(或者下标)。常用模板:typedef long long int LL;const int N=1e6+10;LL h[N],lmax[N],rmax[N],n;//lmax[i]左边最近的比它大的数的下标//rmax[i]右边最近的比它大的数的下标void init(){ stack<int>st; for(int i=1;i<.原创 2022-03-10 20:13:43 · 244 阅读 · 0 评论 -
ACM入门之【单调队列】
单调队列解决的问题:它可以快速的获得一个窗口的最大值(或最小值)。const int N=1e6+10;int a[N],n,k;deque<int>q;void init(){ cin>>n>>k;//总长度为n,窗口大小为k for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=n;i++) { if(q.size()&&i-q.原创 2022-03-10 20:52:32 · 238 阅读 · 0 评论 -
ACM入门之【KMP】
KMP可以O(n)的时间查找出一个字符串在另一个字符串出现的次数和位置。模板:const int N=1e6+10;char a[N],b[N];//让其下标从1开始int n,m,ne[N];//ne[i]表示前i个字符的最长的相等的前后缀void init(){ cin>>n>>a+1>>m>>b+1; for(int i=2,j=0;i<=n;i++) { while(j&&a[原创 2022-03-10 22:26:10 · 300 阅读 · 0 评论 -
ACM入门之【字典树/Trie】
字典树,英文名 trie。顾名思义,就是一个像字典一样的树。常用模板:const int N=1e5+10; //注意: N的大小是所有的字符串的总长度,因为最坏的情况下是一个字符就是一个结点int son[N][26],cnt[N],idx;void insert(string s)//插入{ int p=0; for(int i=0;i<s.size();i++) { int u=s[i]-'a'; if(!son[p][u.原创 2022-03-11 10:52:06 · 239 阅读 · 0 评论 -
ACM入门之【manacher(马拉车)算法】
本文参考了:FREEH在https://www.luogu.com.cn/problem/solution/P3805中的题解。主要用途:O(n)的时间内求一个字符串的最大回文长度。或者 求其所有子串中回文串的个数。算法过程:预处理。由于回文串分为偶回文串和奇回文串,奇偶判断起来比较麻烦,因此我们可以在字符串的首、尾以及各个字符之间添加一些“神奇”字符(不 妨使用$),但是要注意字符串的首添加的字符必须区别于各个字符之间的字符。不难发现,修改后的字符串都变成了奇字符串。几个变.原创 2022-05-18 00:57:52 · 335 阅读 · 0 评论 -
ACM入门之【并查集】
并查集是一种树形的数据结构,顾名思义,它用于处理一些不交集的 合并 及 查询 问题。它支持两种操作:查找:确定某个元素处于哪个子集.合并:将两个子集合并成一个集合。基本模板:const int N=1e5+10;int p[N];int find(int x){ if(x!=p[x]) p[x]=find(p[x]); return p[x];}并查集分为:常见的一般的并查集带权并查集基础习题:836. 合并集合837. 连通块中点的数量...原创 2022-03-11 13:24:49 · 578 阅读 · 0 评论 -
ACM入门之【搜索】
搜索在ACM中是很重要的。搜索一般分为DFS和BFS两大类,下面又划分很多的小类。入门习题:842. 排列数字843. n-皇后问题844. 走迷宫845. 八数码原创 2022-03-11 14:48:07 · 193 阅读 · 0 评论 -
ACM入门之【拓扑排序】
拓扑排序的应用:判断图中是否有环。如果一个图有拓扑排序,说明该图一个没有环。//基本思路就是先将入度为0的点入队,然后再依次扩展减入读。//最后判断点数够n不够就可以了int d[N],st[N],n;vector<int>ans;bool check(){ queue<int>q; for(int i=1;i<=n;i++) if(!d[i]) q.push(i),ans.push_back(i),st[i]=1; while(q.siz原创 2022-03-11 15:30:20 · 385 阅读 · 0 评论 -
ACM入门之【最短路】
朴素Dijkstra模板int g[N][N],dist[N],st[N],n;int Dijkstra(){ memset(dist,0x3f,sizeof dist); dist[1]=0; for(int i=0;i<n-1;i++) { int t=-1; for(int j=1;j<=n;j++) if(!st[j]&&(t==-1||dist[j]<dist[t])) t=j;//找到最近的.原创 2022-03-11 15:44:56 · 203 阅读 · 0 评论 -
ACM入门之【最小生成树】
prim模板int g[N][N],dist[N],n,m,ans;int st[N];void prim(){ memset(dist,0x3f,sizeof dist); dist[1]=0; for(int i=0;i<n;i++) { int t=-1; for(int j=1;j<=n;j++) if(!st[j]&&(t==-1 || dist[j]<dist[t])) t=j; .原创 2022-03-11 22:19:23 · 221 阅读 · 0 评论 -
ACM入门之【二分图】
性质 :如果两个集合中的点分别染成黑色和白色,可以发现二分图中的每一条边都一定是连接一个黑色点和一个白色点。二分图不存在长度为奇数的环(因为每一条边都是从一个集合走到另一个集合,只有走偶数次才可能回到同一个集合。)...原创 2022-03-12 18:54:06 · 216 阅读 · 0 评论 -
ACM入门之【分层图】
例题一:#include<bits/stdc++.h> using namespace std;const int N=1e5*2+10;typedef long long int LL;int h[N],e[N],w[N],ne[N],idx;LL dist[N][15],st[N][15];//dist[i][j] 表示i点距离1的最短距离,且走了j条特殊的边int f[N],n,m,k;void add(int a,int b,int c){ e[idx]=b,w[i原创 2022-04-27 14:55:30 · 343 阅读 · 0 评论 -
ACM入门之【欧拉图】
欧拉通路:图中所有的边恰好经过一次,且经过所有顶点的通路。(简称一笔画)欧拉回路:图中所有的边恰好经过一次,且行遍所有顶点的回路。通过上述可以知道:欧拉通路是不一定回到起点,而欧拉回路一定回到起点。欧拉图:具有欧拉回路的无向图或有向图。半欧拉图:具有欧拉通路但不具有欧拉回路的无向图或有向图。非形式化地讲,欧拉图就是从任意一个点开始都可以一笔画完整个图,半欧拉图必须从某个点开始才能一笔画完整个图。判定的条件:对于无向图,所有边都是连通的。存在欧拉路径的充分必要条件: 度数为奇数的点只能有原创 2022-04-16 00:53:20 · 1568 阅读 · 0 评论 -
ACM入门之【树的直径】
树的直径: 就是树中最长的一条链。求树的直径一般有两种方法。方法一:先随便找个点,dfs一下找到最远的一个点,再用找到的点dfs一下,最远的距离就是直径。方法二:随便找个点dfs一下,存一下最远路和次短路。最短路+次短路+1就是直径。看一下例题:https://ac.nowcoder.com/acm/contest/136/C方法一:#include<bits/stdc++.h>using namespace std;const int N=1e6*2+10;int h原创 2022-04-21 00:09:48 · 354 阅读 · 0 评论 -
ACM入门之【树的重心】
树的重心的定义:对于树上的每一个点,计算其所有子树中最大的子树节点数,这个值最小的点就是这棵树的重心。树的重心的性质:树中所有点到某个点的距离和中,到重心的距离和是最小的。如果有两个重心,那么到它们的距离和一样。以树的重心为根时,所有子树的大小都不超过整棵树大小的一半。两棵树通过一条边相连得到一棵新的树,那么新的树的重心在连接原来两棵树的重心的路径上。在一棵树上添加或删除一个叶子,那么它的重心最多只移动一条边的距离。例题一:#include<bits/stdc++.h>原创 2022-04-25 13:56:20 · 218 阅读 · 0 评论 -
ACM入门之【dfs序列】
DFS 序列是指 DFS 调用过程中访问的节点编号的序列。我们发现,每个子树都对应 DFS 序列中的连续一段(一段区间)。如图所示:红色的编号便是DFS序列的顺序。你可以很容易的理解就是我们平常的DFS遍历树时,到各个点的顺序。你会发现以3号结点为子树的序号是连续的。2、3、4。它是连续的。根据这一性质我们便可以将树转化成区间,来进行一些操作。具体操作如下:我们可以引入一个时间戳的概念。in[u] 表示第一次到达u结点的时间 out[u] 表示将u结点的子树遍历完出来的时间此时以u号结原创 2022-05-06 00:48:01 · 1897 阅读 · 0 评论 -
ACM入门之【欧拉序列】
ACM入门之【dfs序列】欧拉序列概念: 对一棵树进行 DFS,无论是第一次访问还是回溯,每次到达一个结点时都将编号记录下来,可以得到一个长度为2𝑛 − 1的序列,这个序列被称作这棵树的欧拉序列。例子:模板:int len=0,ans[100005];void dfs(int u){ mp[u]=1; ans[++len]=u; for(int i=h[u];i!=-1;i=ne[i]) { int j=e[i]; if(mp[j]) continue; dfs(j);原创 2022-05-16 00:55:19 · 1085 阅读 · 0 评论 -
ACM入门之【平衡树】
有时间补完。平衡树:就是一个平衡的二叉搜索树。平衡树的各个操作的时间为:logn按照对二叉搜索树进行的"操作"可以分为一下几类:有旋转:AVL、Splay、红黑树。无旋转: 替罪羊、Treap。例题://抄的cnt大佬的代码#include<bits/stdc++.h>using namespace std;typedef long long int LL;using namespace std;const int N = 100010, INF = 1.原创 2022-04-25 18:08:49 · 327 阅读 · 0 评论 -
ACM入门之【可持续化数组(Rope)】
一个黑科技,有时候可以用来偷鸡。万一过了呢?rope(可持续化平衡树)需要的头文件#include <ext/rope>命名空间声明:using namespace __gnu_cxx;常用的函数:rope<int> a;a.push_back(x) // 在尾部插入a.append(x) //在尾部插入a.pop_back(x) // 删除最后一个元素a.size() // 返回长度a.insert(int pos, x) // 在pos插入.原创 2022-05-18 01:16:32 · 463 阅读 · 0 评论 -
ACM入门之【连通性】
目录有向图的连通性有向图的连通性对于一个有向图,连通分量: 对于分量中任意两点u,v,必然可以从u走到v,且从v走到u。强连通分量:极大连通分量。也就是说再大点图就不连通了。常用的求有向图的强连通分量的做法是Tarjan算法求强连通分量(SCC) 时间复杂度O(n+m)Tarjan算法求强连通分量的思路是:对于每一个点定义两个时间戳。dfn[u]表示遍历到u的时间戳。low[u]从u开始走,所能遍历到的最小时间戳是什么。u是其所在的强联通分量的最高点,等价于dfn[u]==low[u]原创 2022-04-29 17:14:52 · 710 阅读 · 0 评论 -
ACM入门之【图论习题】
目录P5318 【深基18.例3】查找文献【★】P5318 【深基18.例3】查找文献【★】考察的就是基础的图的遍历。#include<bits/stdc++.h>using namespace std;const int N=1e5+10;vector<int>ve[N];int n,m,st[N];void dfs(int u){ cout<<u<<" "; st[u]=1; for(int i=0;i<v原创 2022-03-21 20:10:35 · 770 阅读 · 0 评论 -
ACM入门之【Miller-Rabin素数测试算法】
参考博文:https://blog.csdn.net/forever_dreams/article/details/82314237模板来自参考博文这个算法可以大概率的判断一个数是不是质数。时间复杂度是O(T×logN) (T为检测轮数)这里只列出模板,因为一般不常用。#include<bits/stdc++.h> using namespace std;typedef long long int LL;int prime[15]={2,3,5,7,11,13,17,19,2.原创 2022-05-03 10:21:15 · 295 阅读 · 0 评论 -
ACM入门之【线性筛】
线性筛模板,时间复杂度O(n)const int N=1e6+10;int prime[N],st[N],cnt,n;void init(int n){ for(int i=2;i<=n;i++) { if(!st[i]) prime[cnt++]=i; for(int j=0;prime[j]<=n/i;j++) { st[i*prime[j]]=1; if(i%prime[原创 2022-03-13 11:11:28 · 132 阅读 · 0 评论 -
ACM入门之【约数】
求最大共约数模板int gcd(int a,int b){return b?gcd(b,a%b):a;}如果 N = p1^c1 * p2^c2 * ... *pk^ck约数个数: (c1 + 1) * (c2 + 1) * ... * (ck + 1)约数之和: (p1^0 + p1^1 + ... + p1^c1) * ... * (pk^0 + pk^1 + ... + pk^ck)872. 最大公约数869. 试除法求约数870. 约数个数871. 约数之和...原创 2022-03-13 11:18:46 · 147 阅读 · 0 评论 -
ACM入门之【快速幂】
快速幂模板typedef long long int LL;LL quick_mi(LL a,LL b,LL p){ LL sum=1; while(b) { if(b&1) sum=sum*a%p; b>>=1; a=a*a%p; } return sum%p;}875. 快速幂876. 快速幂求逆元原创 2022-03-13 12:45:01 · 206 阅读 · 0 评论 -
ACM入门之【矩阵快速幂】
矩阵快速幂其实是一个用于加速计算的一个算法。矩阵快速幂和我们普通的数的快速幂是没有啥太大的区别的。不过一个是数,一个是矩阵。矩阵快速幂的应用: 矩阵加速递推。例如:如果有一道题目让你求斐波那契数列第n项的值,最简单的方法莫过于直接递推了。但是如果n的范围达到了 1018级别,递推就不行了,稳 TLE。考虑矩阵加速递推。看一个模板题来了解矩阵快速幂:#include<bits/stdc++.h>using namespace std;const int N=110;const.原创 2022-05-03 15:20:38 · 793 阅读 · 0 评论 -
ACM入门之【组合数】
组合数模板一const int N=2010;const int mod=1e9+7;int C[N][N],t,a,b;//C[i][j] 从i里面选j个void init(){ for(int i=0;i<N;i++) { for(int j=0;j<=i;j++) { if(j==0) C[i][j]=1; else C[i][j]=(C[i-1][j-1]+C[i-1][j])%m原创 2022-03-13 13:18:26 · 718 阅读 · 0 评论