算法模板
Wizard go
这个作者很懒,什么都没留下…
展开
-
和谐宿舍(贪心+二分)
和谐宿舍我的某室友学过素描,墙上有n张他的作品。这些作品都是宽度为1,高度不定的矩形,从左到右排成一排,且底边在同一水平线上。 宿舍评比就要来了,为了及格,我们决定买不多于m块的矩形木板,把这些作品和谐掉。要求木板也从左到右排成一排,且底边与作品的底边在同一水平线上。 在能够把所有作品和谐掉的前提下,我们希望最大的那块木板的面积最小,问最大木板的面积。输入格式 第一行两个数n和m,表示作品数和木板数; 第二行n个数Hi,表示从左到右第i个作品的高度。输出格式 一行一个数ans,表原创 2022-04-04 18:49:05 · 831 阅读 · 0 评论 -
求乘法逆元
已知a*x≡1(mod m) ,求a的逆元解法1:若m是质数,可用快速幂求解int qmi(int a, int b, int p){ int res=1; while(b) { if(b&1) res=1ll*res*a%p; b>>=1; a=1ll*a*a%p; } return res;}//a的逆元:x=a^m-2int x=qmi(a,m-2,m);解法2:若m不是质数,只能用扩展欧几里得算法//扩展欧几里得求逆元int exgcd原创 2022-02-24 09:50:20 · 64 阅读 · 0 评论 -
19.堆排序
堆中根节点存储的是最小值,每一个节点的左右儿子都是大于或等于该节点。插入元素:将新元素插在最后,heap[++size]=x,再依次与其父节点比较,若该元素小于其父节点,则和父节点交换位置,循环直到正确位置。删除元素:用最后一个元素覆盖要删除的元素,并删除最后一个元素,heap[k]=heap[size–], 再通过down和up操作到正确位置。修改元素:heap[k]=x,再执行down和up操作。对于父节点x,其左儿子为2x,右儿子为2x+1;(从1开始)// h[N]存储堆中的值, h原创 2022-01-27 16:24:24 · 67 阅读 · 0 评论 -
18.并查集
基本操作:1.将两个集合合并2.查询两个集合是否在同一个集合中基本原理:每个集合用一颗树来表示,树根的编号就是整个集合的编号,每个节点存储它的父节点,p[x]表示x的父节点。对于根结点,p[x]=x。问题1:如何判断树根,看根节点x是否等于p[x]问题2:如何查询元素所属的集合编号,从该元素向上搜索,直至找到根节点。递归方式:int find(int x){ if(p[x]!=x) p[x]=find(p[x]); return p[x];}循环方式:int find原创 2022-01-26 13:33:44 · 175 阅读 · 0 评论 -
17.Tire树
维护一个字符串集合,支持两种操作:I x 向集合中插入一个字符串 x;Q x 询问一个字符串在集合中出现了多少次。共有 N 个操作,输入的字符串总长度不超过 105,字符串仅包含小写英文字母。维护一个字符串集合,支持两种操作:I x 向集合中插入一个字符串 x;Q x 询问一个字符串在集合中出现了多少次。共有 N 个操作,输入的字符串总长度不超过 105,字符串仅包含小写英文字母。输入格式第一行包含整数 N,表示操作数。接下来 N 行,每行包含一个操作指令,指令为 I x 或 Q x 中原创 2022-01-26 11:57:01 · 77 阅读 · 0 评论 -
17.单调栈和单调队列
单调栈常见模型:找出每个数左边离它最近的比它大/小的数int tt = 0;for (int i = 1; i <= n; i ++ ){ while (tt && check(stk[tt], i)) tt -- ; stk[ ++ tt] = i;}单调队列常见模型:找出滑动窗口中的最大值/最小值int hh = 0, tt = -1;for (int i = 0; i < n; i ++ ){ while (hh <= t原创 2022-01-25 11:23:37 · 132 阅读 · 0 评论 -
16.栈和队列
栈// tt表示栈顶int stk[N], tt = 0;// 向栈顶插入一个数stk[ ++ tt] = x;// 从栈顶弹出一个数tt -- ;// 栈顶的值stk[tt];// 判断栈是否为空if (tt > 0){}队列//hh表示队头,tt表示队尾int q[N],hh=0,tt=-1//入队q[++t]=x;//出队hh++;//队头q[hh];//看队列是否为空if(hh<=tt){}循环队列// hh 表示队头,原创 2022-01-24 11:37:49 · 184 阅读 · 0 评论 -
15.数组模拟双链表
// e[]表示节点的值,l[]表示节点的左指针,r[]表示节点的右指针,idx表示当前用到了哪个节点int e[N], l[N], r[N], idx;// 初始化void init(){ //0是左端点,1是右端点 r[0] = 1, l[1] = 0; idx = 2;}// 在节点a的右边插入一个数xvoid insert(int a, int x){ e[idx] = x; l[idx] = a, r[idx] = r[a]; l原创 2022-01-24 11:26:30 · 230 阅读 · 0 评论 -
14.数组模拟单链表
//head表示头指针,e[N]表示当前节点的值,ne[N]表示当前节点的next指针,idx表示当前用到哪个节点int head, e[N],ne[N],idx;void init(){ head=-1; idx=0;}//在链表头插入一个元素void insert(int a){ e[idx]=a; ne[idx]=head; head=idx++;}//删除头结点void remove(){ head=ne[head];}...原创 2022-01-24 11:01:12 · 56 阅读 · 0 评论 -
13.区间合并
1.按照区间左端点排序2.区间有如下几种情况:(1)区间1包含区间2(2)区间1和区间2有交集,即区间2的左端点<=区间1的右端点。(3)区间1和区间2没有交集,即区间2的左端点>区间1的右端点。typedef pair<int,int> PII;void merge(PII &segs){ sort(segs.begin(), segs.end());//排序 vector<PII> res;//用来存储合并后的区间 int st=-2e9,原创 2022-01-19 16:03:38 · 53 阅读 · 0 评论 -
12.离散化
对于一个值域很大的数组,如109,里面只包含稀疏的元素,我们没办法直接开辟一个一样大的数组来遍历对数组中的元素进行操作,这时我们就需要进行离散化处理。比如对于一个109的数组,我们要操作的只有下面5个元素我们可以用vector存取上述该元素的所有索引 [ 1,2,10,100,10000 ]现在的数组空间就变成vector.size();接下来我们只需要用二分法对每一个索引进行定位,求出对应离散化的值这样我们就将需要操作的元素映射到一个低维数组。代码模板:vector<int>原创 2022-01-19 12:09:57 · 201 阅读 · 0 评论 -
11.位运算
求一个数n的二进制表示的第k位是多少n>>k&1求一个二进制数n中1的个数: n&-n = n&(~n+1)int lowbit(int n){ return n&-n;//返回最末尾的1}int count=0;while(n){ n-=lowbit(n); count++;}原创 2022-01-19 10:33:56 · 37 阅读 · 0 评论 -
10.双指针
先使用暴力求解,再看i,j之间是否有联系进行优化for (int i = 0, j = 0; i < n; i ++ ){ while (j < i && check(i, j)) j ++ ; // 具体问题的逻辑}练习题:最初不重复子序列原创 2022-01-19 09:49:38 · 165 阅读 · 0 评论 -
9.一维差分和二维差分
一维差分an=b1+b2+·······+bn,a是前缀和数组,b是差分数组bn=an-an-1要在原数组某个区域[l,r]加上c,只需要b[l]+=c;b[r+1]-=c;void insert(int l,int r,int c){ b[l]+=c; b[r+1]-=c}//前缀和for(int i=1;i<=n;i++) b[i]+=b[i-1];二维差分在(x1,y1),(x2,y2)的区域加上c,void insert(int x1,int y1,int x原创 2022-01-18 15:31:06 · 53 阅读 · 0 评论 -
8.二维前缀和
#include<iostream>const int N=1010;int n,m,q;int a[N][N],s[N][N];int main(){ scanf("%d%d%d",&n,&m,&q); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",a[i][j]); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++原创 2022-01-17 17:55:59 · 229 阅读 · 0 评论 -
6.高精度乘法I
A是大数,b是小数。方法与加分类似,用A的每一位乘b,t/10记录进位,t%10保留个位。#include<iostream>#include<vector>using namespace std;vector<int> mul(vector<int> &A,int B){ vector<int> C; int t=0; for(int i=0;i<A.size() || t;i++) {原创 2022-01-17 15:22:19 · 64 阅读 · 0 评论 -
5.高精度减法
对于两个数A和B;如果A<B;-(B-A)如果A>=B;A-B与加分相同,先倒序放到两个数组,对于每一个如果a>b,那么直接a-b,如果a<b;需要借位,a+10-b判断A和B谁大bool cmp(vector<int> &A,vector<int> &B){ if(A.size()!=B.size()) return A.size()-B.size(); for(int i=A.size()-1;i>=0;i--)原创 2022-01-16 11:19:25 · 86 阅读 · 0 评论 -
4.高精度加法
对于两个A和b,假设A是大数,b是小数,两者要想加,为了保证不溢出。A:123456789b:1234把A和b分别倒序存放在数组中A:987654321b:4321接下来我们只需要像人工执行加分一样,从第一位开始相加,进1就把它加到下一位vector<int> add(vector<int> &A,vector<int> &B){ vector<int> C; int t=0; for(int i=0;i<A.siz原创 2022-01-16 10:08:27 · 81 阅读 · 0 评论 -
3.整数二分和浮点数二分
整数二分1.先写一个check函数2.判定在check的情况下(true和false的情况下),如何更新区间。3.在check(m)==true的分支下是:l=mid的情况,中间点的更新方式是m=(l+r+1)/2r=mid的情况,中间点的更新方式是m=(l+r)/2int l=0,r=n-1;while(l<r){ int mid=l+r>>1; if(check(mid)) r=mid; else l=mid+1; }}int l=0,r=n-1;whi原创 2022-01-15 17:24:00 · 76 阅读 · 0 评论 -
2.归并排序
归并排序1.确定分界点:mid=(l+r)/22.递归排序left,right3.归并合二为一int tmp[N];//辅助数组存元素void merge_sort(int q[],int l,int r){ if(l>=r) return; int mid=l+r>>1;//确定中点为分界点 merge_sort(q,l,mid),merge_sort(q,mid+1,r); int k=0,i=l,j=mid+1;//i,j分别指向左半段和右半段的开头 while原创 2022-01-15 10:50:45 · 131 阅读 · 0 评论 -
1.快速排序
快速排序1.确定分界点x2.调整元素使得分界点左边的元素小于x,右边的元素大于x。此时就分成了两段。3.递归左右两段算法模板void quick_sort(int q[],int l,int r){ if(l>=r) return; int x=q[l+r>>1];//确定分界点 int i=l-1,j=r+1;//从两侧出发,执行时左右落到的就都是头尾元素 while(l<r) { do i++; while(q[i]<x); do j--; w原创 2022-01-15 09:58:22 · 91 阅读 · 0 评论