Acwing算法模板
y总复读机
折叠的饼干
这个作者很懒,什么都没留下…
展开
-
快速幂模板
求 m^k mod p,时间复杂度 O(logk)。int qmi(int m, int k, int p){ int res = 1 % p, t = m; while (k) { if (k&1) res = res * t % p; t = t * t % p; k >>= 1; } return res;}原创 2021-11-15 14:11:04 · 280 阅读 · 2 评论 -
计数类dp——整数划分
整数划分和完全背包很像#include <iostream>using namespace std;const int mod=1e9+7;const int N=1010;int dp[N][N];int main(){ int n; scanf("%d",&n); for (int i = 0; i <= n; i ++)dp[i][0] = 1; for(int i=1;i<=n;i++){原创 2021-10-01 14:30:35 · 126 阅读 · 0 评论 -
sync_with_stdio和tie
sync_with_stdio这个函数是一个“是否兼容stdio”的开关,C++为了兼容C,保证程序在使用了std::printf和std::cout的时候不发生混乱,将输出流绑到了一起。tietie是将两个stream绑定的函数,空参数的话返回当前的输出流指针。在默认的情况下cin绑定的是cout,每次执行 << 操作符的时候都要调用flush,这样会增加IO负担。可以通过tie(0)(0表示NULL)来解除cin与cout的绑定,进一步加快执行效率。ACM应用在ACM里,经常出现转载 2021-08-24 16:49:56 · 171 阅读 · 0 评论 -
时间复杂度分析
c++ 1s可以算107到108次一般算法题限制时间为1s或2s在这种情况下,控制在10^7较好下面给出在不同数据范围下,代码的时间复杂度和算法该如何选择:1.n≤30 => 指数级别dfs+剪枝,状态压缩dp2.n≤100 => O(n3)floyd,dp,高斯消元3.n≤1000 => O(n2),O(n2logn)dp,二分,朴素版Dijkstra、朴素版Prim、Bellman-Ford4.n≤10000 => O(n(n)\原创 2021-08-12 16:03:10 · 1929 阅读 · 0 评论 -
贪心——推公式——耍杂技的牛
耍杂技的牛将所有牛按照wi+si从小到大的顺序排,危险系数是最小的结果是其中的最大值#include <iostream>#include <algorithm>using namespace std;const int N=501000;typedef pair<int,int>PII;PII cow[N];int main(){ int n,sum=0; scanf("%d",&n); for(int i=原创 2021-08-09 19:54:36 · 114 阅读 · 0 评论 -
贪心——绝对值不等式——货仓选址
货仓选址对于a,b两点L=|x-a|+|x-b|,最优解一定在a和b之间L>=b-af(x)=|x1-x|+|x2-x|+……+|xn-x|=(|x1-x|+|xn-x|)+(|x2-x|+|xn-1-x|)+……≥xn-x1+xn-1-x2+……最小方案为:为偶数个:x取在中间两个数之间为奇数个:x取在中位数#include <iostream>#include <algorithm>using namespace std;const int N=原创 2021-08-09 18:34:22 · 163 阅读 · 0 评论 -
贪心——排序不等式——排队打水
排队打水总共n人T=t1*(n-1)+t2*(n-2)+……+tn按从小到大的顺序排序,等待时间最小#include <iostream>#include <algorithm>#include <queue>using namespace std;typedef long long LL;const int N=1e5+10;int t[N];int main(){ int n; scanf("%d",&n); f原创 2021-08-09 17:27:45 · 114 阅读 · 0 评论 -
贪心——Huffman树——合并果子
合并果子dp问题中还有一道类似的合并石子,不同点在于,合并石子必须是相邻的做法:每次从堆中挑出两个权值最小的进行合并,最小的两个点一定是深度最深的点并且可以互为兄弟结点#include <iostream>#include <algorithm>#include <queue>using namespace std;int main(){ int n; scanf("%d",&n); priority_queue <i原创 2021-08-09 17:03:33 · 115 阅读 · 0 评论 -
贪心算法——区间问题——区间选点(最大不相交区间数量)、区间分组、区间覆盖
贪心选择当前最优情况,通过局部最优解找到全局最优解区间问题常见思路:排序:按左端点/右端点/双关键字排序区间排序步骤:1.将每个区间按照右端点从小到大排序2.从前往后枚举每个区间如果当前区间已经包含点,换下一个区间如果当前区间不包含点,尽量选取区间后面的点#include <iostream>#include <algorithm>using namespace std;const int N=1e5+10;struct Range{ int原创 2021-08-09 16:18:37 · 714 阅读 · 2 评论 -
dp记忆化搜索
滑雪1.状态表示:i.集合:dp[i][j]所有从(i,j)开始滑的路径ii.属性:Max2.状态计算:按第一步从哪个方向滑把路径分为4类#include <iostream>#include <cstring>#include <algorithm>using namespace std;const int N=310;int w[N][N];int f[N][N];int dx[4]={0,-1,0,1};int dy[4]={1,0,-原创 2021-08-08 15:04:55 · 262 阅读 · 0 评论 -
树形dp——没有上司的舞会
没有上司的舞会1.状态表示i.集合f[u,0] 所有从以u为根结点的子树中进行选择,并且不选u的方案f[u,1] 所有从以u为根结点的子树中进行选择,并且选u的方案ii.属性Max2.状态计算设根结点u的两个子树的根结点为s1,s2不选u时,根结点可选可不选f[u,0]=Σmax(f[si,0],f[si,1])选u时,根结点不能选f[u.1]=Σf[si,0]时间复杂度:n个职员去或不去,所以状态个数为 2n每个状态在枚举时,需要算的是它所有儿子,所有儿子数量加到一块为树的原创 2021-08-08 11:20:31 · 100 阅读 · 0 评论 -
状态压缩dp——蒙德里安的梦想、最短Hamilton路径(旅行商问题)
蒙德里安的梦想当横向的小方格放好后,纵向小方格的位置是确定的,即总共数量等于横着摆放的小方格的方式的数量#include <iostream>#include <algorithm>#include <cstring>using namespace std;const int N=12,M=1<<N;long long dp[N][M];//dp[i][j]表示第i列总方案数//j表示第i列的状态,即第i-1列放入的小方块在第i列占用了哪原创 2021-08-08 09:48:25 · 225 阅读 · 0 评论 -
区间dp详解——石子合并
石子合并1.状态表示dp[i][j]i.集合:所有将第i堆石子到第j堆石子合并成一堆石子的合并方式ii.属性:Min,算最小值时要初始化成最大的2.状态计算将i~j的合并方式以最后两堆的合并方式分成k类,总共的最小代价是每一类的最小代价取MIn区间长度为1时,和并不需要代价,所以区间长度从二开始#include <iostream>#include <algorithm>using namespace std;const int N=310,INF=0x3f3原创 2021-08-07 10:34:12 · 429 阅读 · 0 评论 -
c++常用STL
参考网站c++ referencevector变长数组,倍增思想初始化vector<int>a(10);//长度为10的vectorvector<int>a(10,-3)//长度为10,每个值为-3vector<int>a[10];//vector数组,定义了10个vector常用函数//这两个函数所有容器都有,时间复杂度为O(1)a.size();//返回元素个数a.empty();//返回是否是空的a.clear();//并不是所有容器都有原创 2021-07-14 14:19:24 · 114 阅读 · 0 评论 -
线性dp例题详解——数字三角形、最长上升子序列、最长公共子序列、最短编辑距离、编辑距离
数字三角形1.状态表示dp[i][j]i.集合:所有从起点走到(i,j)的路径ii.属性:Max2.状态计算为了方便计算,如果出现i-1这样的下标,最好i从1开始。动态规划问题时间复杂度一般等于状态数量×转移计算量做法:自顶向上也可以自底向上做#include <iostream>#include <algorithm>using namespace std;const int INF=1e9;const int N=510;int num[N][N]原创 2021-08-07 08:59:42 · 223 阅读 · 0 评论 -
背包问题详解
背包问题0-1背包dp问题思路(一)状态表示(i,j)//i为物品个数,j为背包最大容量1.集合(1)所有选法(2)条件i.只从前i个物品里选ii.选择物品总容量≤j2.属性Max,(Min,数量)(二)状态计算1. 集合划分f(i,j)1.不含第i件物品(在1~i-1件物品里选)—f(i-1,j)2.当j≥v[i]时 ,可能含第i件物品(在第1~i件物品里选,必须包含i)—f(i-1,j-v[i])+w[i]f(i,j)=max( f(i-1,j) , f(原创 2021-08-05 16:26:53 · 245 阅读 · 0 评论 -
数论模板-素数筛、约数、欧拉函数
数论质数的判定:试除法在大于1的整数中,如果只包含1和本身这两个约数,就被称为质数/素数一定为·O(sqrt(n))不推荐:i*i<n 存在溢出风险i<n/i 一定不会溢出i<sqrt(n)每次都要调用函数分解质因数:试除法不一定为O(sqrt(n))最好O(logn),最坏O(sqrt(n))根据算术基本定理,不考虑排列顺序的情况下,每个正整数都能够以唯一的方式表示成它的质因数的乘积。n=p1a1 x p2a2 x p3a3 x…… x pnan比如一个数原创 2021-07-31 20:43:17 · 307 阅读 · 2 评论 -
二分图模板
#二分图如何判别一个图是不是二分图-染色法O(n+m)DFS求二分图的最大匹配-匈牙利算法O(mn) 实际时间复杂度远小于O(mn)原创 2021-07-30 10:38:14 · 85 阅读 · 0 评论 -
最小生成树
最小生成树最小生成树对应的图是无向图Prim稠密图 朴素版 O(n2)集合:当前已经在连通块当中的所有点Dijkstra迭代n-1次 上来已经选中了一个点Prim迭代n次 第一个点要选典型题:铺路最小生成树由于没有环,正边和负边都可以稀疏图 堆优化版 O(mlogn)不常用Kruskal O(mlogm)时间复杂度主要花在排序上主要用于稀疏图...原创 2021-07-23 10:18:07 · 107 阅读 · 0 评论 -
Trie树(字典树)模板
Trie 树高效的存储和查找字符串集合的数据结构存储公共前缀#include <iostream>using namespace std;const int N=100010;int son[N][26],cnt[N];int idx=0;//下标是0的点,既是根结点,又是空结点void insert(char str[]){ int p=0; for(int i=0;str[i];i++){//c++ char[]末尾是'/0'可作为停止条件 i原创 2021-07-21 19:08:41 · 99 阅读 · 1 评论 -
最短路问题
常见的最短路问题的算法选择:有向图和无向图的最短路没有区别,没有区分有向边无向边1.单源最短路一个点到其他所有点的距离单源:即只有一个起点(1)所有边权都是正数n为节点数,m为边数①朴素Dijkstra算法适合稠密型时间复杂度O(n2)用邻接矩阵存②堆优化Dijkstra 适合边稀疏型当边稠密时,n为点数,m为边数时间复杂度O(mlogn)m≈n2O(n2logn)用邻接表存(基于贪心)Dijkstra采用贪心选择思想,通过求解局部最优解来求解全局最优解。单源最短路径S原创 2021-07-21 19:02:08 · 634 阅读 · 0 评论 -
树和图模板
图的存储方式可以将树归为一种特殊的图,无环连通图有向图a->bb->a无向图a–b无向图是一种特殊的有向图,所以只用考虑有向图就可以了存储方式邻接矩阵**g[a][b]**表示从a到b的一条边如果有重边保留一条就可以了比较浪费空间,空间复杂度O(n2)适合稠密图,用的比较少无权用bool,有权用int邻接表用的比较多的是邻接表N个点,每个点一条单链表单链表:head,e[N],ne[N],idx;邻接表:h[N],e[N],ne[N],idx;有向图才有原创 2021-07-17 08:55:30 · 118 阅读 · 0 评论 -
深度优先搜索和广度优先搜索
DFS 栈按高度存 空间O(logn) 不具有最短性顺序 可以把DFS当作递归,回溯时一定要恢复现场例题:全排列#include <iostream>using namespace std;int n;const int N=100010;int nums[N];bool f[N];void dfs(int t){ if(t==n){ for(int i=0;i<n;i++){ printf("%d ",nums[i]);原创 2021-07-15 20:28:37 · 122 阅读 · 0 评论 -
数组模拟堆模板
堆1.插入一个数添加头结点比较困难,添加尾结点十分容易heap[++size]=x;up(size);2.求集合中的最小值heap[1];3.删除最小值删除头结点非常困难,删除尾结点非常方便heap[1]=heap[size];size--;down(1);4.删除任意元素heap[k]=heap[size];size--;down(k);//只有heap[k]变大时执行up(k);//只有heap[k]变小时执行5.修改任意元素heap[k]=x;down原创 2021-07-14 22:27:11 · 171 阅读 · 0 评论 -
哈希表模板
哈希表把大的区间映射到小的区间,一般为0~Nx∈(-109,109)x mod 105∈(0,105) 模数一般要取成质数,且该质数要离2的整数次幂尽可能远,这样冲突的概率是最小的。可能出现冲突,按冲突的处理方式可分为两种存储结构1.开放寻址法2.拉链法常用操作:1.添加2.查找3.删除 一般不会真的删除,只会开一个bool数组标记字符串哈希方式...原创 2021-07-14 09:12:55 · 330 阅读 · 0 评论 -
并查集模板
并查集作用:1.将两个集合合并2.询问两个元素是否在一个集合当中暴力做法:O(n)belong[x]=x1.把belong[x]=a改为b O(n)2.belong[x1]==belong[x2] O(1)而用并查集复杂度:近乎O(1)每个集合以树的形式维护’每个集合编号是它根结点的标号每个点都存储其父结点标号,就能通过其父结点编号快速找到该结点是属于哪个集合的p[x]表示x的父结点问题1:如何判断某一结点是不是根结点if(p[x]]==x)问题2:如何求x的集合编号向原创 2021-07-12 14:55:06 · 146 阅读 · 0 评论 -
数组模拟链表模板
链表与邻接表数组模拟链表优点:速度快数组模拟链表被称为静态链表静态链表相对于动态链表非常快new的过程很耗时间数组模拟单链表最常用的是 邻接表邻接表相当于n个链表主要应用:存储树和图eg.最短路问题,最小生成树问题,最大流问题head头节点下标(非头结点)e[i] i点的值ne[i] i点的next指针idx 当前用到的点初始化void init(){ idx=0; head=-1;}插入到头结点void add_to_head(){ e[idx]原创 2021-07-11 12:01:06 · 159 阅读 · 0 评论 -
数组模拟栈和队列模板
拿数组模拟STL:速度快栈st[N]tt栈顶st[++t]=x;tt--;if(tt>0)not empty单调栈应用:给定一个序列,找到每一个数左边离它最近的数拓展·:右边最近,右边最近且大于它当ax>=ay且x<y,则ax永远不会作为答案输出每个元素只会进栈一次,出栈一次,时间复杂度为O(n)例题 单调栈给定一个长度为 N 的整数数列,输出每个数左边第一个比它小的数,如果不存在则输出 −1。输入格式第一行包含整数 N,表示数列长度。第二行包含 N原创 2021-07-11 10:35:22 · 106 阅读 · 0 评论 -
区间合并模板
区间合并如果两个区间有交集,将这两个区间合并为一个区间注意:只有端点相交,也进行区间合并1.按区间左端点排序,选取最左区间作为当前维护的区间其后的区间与当前维护的区间可能有三种情况①包含于被维护的区间②与被维护的区间相交③与被维护的区间不相交2.扫描整个区间,将所有可能有交集的区间合并①已包含,不用管②扩大被维护区间③当前被维护区间可提交,将被维护区间设定为当前区间例题:区间合并#include<iostream>#include <vector>#原创 2021-07-09 12:18:00 · 145 阅读 · 0 评论 -
前缀和,差分模板
前缀和对于数组a1,a2,a3…an前缀和Si=a1+a2+…+an,S0=a0对于al,al+1,al+2…ar可以用Sr-Sl-1表示复杂度为O(1)例题#include <iostream>using namespace std;const int N=100010;int main(){ int n,m,a[N],s[N]; cin>>n>>m; for(int i=1;i<=n;i++){原创 2021-07-09 10:57:13 · 150 阅读 · 0 评论 -
离散化模板
离散化概念将值域为0~109,个数为105的数一一映射到0,1,2,3……上eg.a[]:122,333,9,0,111对应0,1,2,3,4适用于值域跨度很大,但非常稀疏的情况把保序离散化的下标映射到0,1,2,3……上注意1.a[]中可能存在重复元素->去重erase(unique(),end())unique的实现:1)是第一个2)和前面的数不一样 ,即nums[i]!=nums[i-1]2.如何算出a[i]离散化后的值->二分模板vector<in原创 2021-07-08 22:57:45 · 137 阅读 · 0 评论 -
位运算模板
n的二进制表示中,第k位数是末尾是第0位1.把n的第k为移到末尾 n>>k2.看最后一位数是几 n&1n>>k&1lowbit(x):返回x的最后一位1x&-x-x=~x+1eg.x=1010 lowbit(x)=10x=11001000 lowbit(x)=1000例题:#include <iostream>using namespace std;const int N=100010;int lowbit原创 2021-07-08 15:44:02 · 89 阅读 · 0 评论 -
双指针算法模板
双指针算法1.在一个序列上 eg.快排2.在两个序列上 eg.归并排序for(int i=0,j=0;i<n;i++){ while(j<i&&check(i,j))j++;//这里注意j<i}作用:优化h双层for循环O(n^2)时间复杂度为O(n)i和j不会跨越(始终一个在一个的另一边)例题:划分单词输入一个字符串,输出字符串里每个单词,单词之间用空格隔开#include <iostream>#include <string原创 2021-07-08 15:22:39 · 171 阅读 · 0 评论 -
高精度模板
1.A+B2.A-B3.A*a4.A/alen(A)<=10^6a<=10^9用数组存每一位,从低位存到高位A+B#include<iostream>#include <vector>using namespace std;vector<int> add(vector<int>a,vector<int>b){ vector<int>c; int t=0; for(int i=0;原创 2021-07-07 19:02:35 · 79 阅读 · 0 评论 -
二分查找模板
二分查找二分的本质不是单调性,没有单调性也可以用二分二分的本质是边界,在区间上定义某种性质,使得整个区间一分为二,一半区间满足这种性质,另一半区间不满足这种性质,那么二分可以寻找到性质的边界既可寻找绿颜色边界,也可寻找红颜色边界红色为不满足性质的区间,绿色为满足性质的区间一.找满足性质的边界值(即绿色区间边界值)1.找中间值mid=(l+r)>>1;2.check(mid)满足性质时为true3.如果check(mid)=true说明在右边区间(绿色)找到了mid,应该到[l原创 2021-07-07 09:45:45 · 561 阅读 · 0 评论 -
快速排序、归并排序模板
快速排序一.确定分界点q[l]/q[r]/q[(l+r)/2]/随机二.调整范围左边<=x,右边>=x三.递归处理左右两段交换完还要移动一格,所以需要先移动才能取到真正的边界模板1:以左边作为基准,注意递归边界的选择#include<iostream>using namespace std;const int N=1e6+10;int n;int q[N];void quicksort(int q[],int l,int r){ if(l==r)re原创 2021-07-06 19:10:50 · 250 阅读 · 0 评论