主页
最近更新
五一普转提笔记 Day-1
最后更新于 2025-05-01 20:39:25
作者
GZH___666
分类
算法·理论
复制 Markdown
更新文章内容
# 清北学堂五一集训Day-1 ## 上午 ### 1.在比赛时尽量使用'\n',不要用endl ### 2.队列(FIFO) #### stl队列: ```cpp #include<queue> //#include<bits/stdc++.h> using namespace std; queue<int> q; //queue<队列里面的元素类型> 变量名; int main() { q.push(233); q.push(2233);//向队列里面加入一个元素 q.pop();//从队列中删除一个元素 删除是队列头的元素 233 void类型没有返回值 int x = q.front();//获取队列头元素 2233 cout << q.size() << endl;//获取队列剩余的元素个数 1 } ``` #### 手写队列: ```cpp #include<bits/stdc++.h> using namespace std; struct queue { int a[1000]; int head=1;//队列头在哪里 int tail=0;//队列尾巴在哪里 void push(int x) { tail ++; a[tail] = x; } void pop() { head++; } int size() { return tail-head+1; } int front() { return a[head]; } }q; int main() { q.push(233); q.push(2233);//向队列里面加入一个元素 q.pop();//从队列中删除一个元素 删除是队列头的元素 233 void类型没有返回值 int x = q.front();//获取队列头元素 2233 cout << q.size() << endl;//获取队列剩余的元素个数 1 } ``` ### 3.栈(FILO) #### stl队列: ```cpp #include<stack> //#include<bits/stdc++.h> using namespace std; stack<int> q; //stack<队列里面的元素类型> 变量名; int main() { q.push(233); q.push(2233);//向栈里面加入一个元素 q.pop();//从栈中删除一个元素 删除是队列头的元素 2233 void类型没有返回值 int x = q.top();//获取栈顶部元素 233 cout << q.size() << endl;//获取栈剩余的元素个数 1 } ``` ### 4.双指针 1个从前开始,1个自后向前 ```cpp int main() { cin >> n; for (int i=1;i<=n;i++) cin >> a[i]; cin >> m; int sum=0; for (int l=1,r=1;l<=n;sum-=a[l],l++) { while (sum<=m && r<=n) { sum += a[r]; r++; } if (sum>m) { r--; sum -= a[r]; } ans = max(ans,r-l);//a[l] ~ a[r-1] } } ``` ### 5.双端队列(deque) ```cpp #include<deque> using namespace std; deque<int> q;//双端队列 //q.push_front() 从前面加入 //q.pop_front() 从前面删除 //q.front() 询问前面的数是多少 //q.push_back() 从后面加入 //q.pop_back() 从后面删除 //q.back() 询问后面的数是多少 int a[maxn]; void push(int i)//单调队列的插入 插入下标为i的元素 要保证队列单调递增 { while (q.size() > 0 && a[q.back()] >= a[i]) q.pop_back(); q.push_back(i); } int main() { cin >> n; for (int i=1;i<=n;i++) cin >> a[i]; cin >> m;//所有长度为m的区间的最小值 for (int i=1;i<=n;i++) { push(i);//向单调队列里面加入a[i]这个元素 if (i-m == q.front()) q.pop_front();//把a[i-m]这个数删掉 if (i>=m)//区间长度已经超过m了 需要取出最小值 cout << a[q.front()] << "\n"; } } ``` ### 6.堆: #### 1.大根堆 ```cpp #include<queue> //#include<bits/stdc++.h> using namespace std; priority_queue<int> q; //大根堆 struct rec { int a,b; }; //如果要把结构体 放入 stl比大小 只能重载小于号 bool operator<(const rec &x,const rec &y) { return x.a + x.b > y.a + y.b; } priority_queue<rec> qq;//取出a+b最小的结构体 int main() { q.push(233); q.push(2233);//向堆里面加入一个元素 q.pop();//从堆中删除一个元素 删除是堆中最大的元素 2233 void类型没有返回值 int x = q.top();//获取堆中最大元素 233 cout << q.size() << endl;//获取堆剩余的元素个数 1 } ``` #### 2.小根堆: ##### ①stl小根堆: ```cpp #include<queue> #include<bits/stdc++.h> using namespace std; priority_queue< int , vector<int> , less<int> > q; struct rec { int a,b; }; //如果要把结构体 放入 stl比大小 只能重载小于号 bool operator<(const rec &x,const rec &y) { return x.a + x.b > y.a + y.b; } priority_queue<rec> qq;//取出a+b最小的结构体 int main() { q.push(-233); q.push(-2233);//向堆里面加入一个元素 q.pop();//从堆中删除一个元素 删除是堆中最大的元素 2233 void类型没有返回值 int x = q.top();//获取堆中最大元素 233 cout << q.size() << endl;//获取堆剩余的元素个数 1 } ``` ##### ②通过对大根堆取负号实现: ```cpp #include<queue> //#include<bits/stdc++.h> using namespace std; priority_queue<int> q; //大根堆 //小根堆最简单的方法:取负号 struct rec { int a,b; }; //如果要把结构体 放入 stl比大小 只能重载小于号 bool operator<(const rec &x,const rec &y) { return x.a + x.b > y.a + y.b; } priority_queue<rec> qq;//取出a+b最小的结构体 int main() { q.push(-233); q.push(-2233);//向堆里面加入一个元素 q.pop();//从堆中删除一个元素 删除是堆中最大的元素 2233 void类型没有返回值 int x = q.top();//获取堆中最大元素 233 cout << q.size() << endl;//获取堆剩余的元素个数 1 } ``` ### 7.heapa: ```cpp struct heap{ int a[1010];//堆的每一个元素 int n=0; int top()//询问最大值 { return a[1]; } void push(int x)//插入一个数 {//O(logn) n++;a[n] = x; int p=n; while (p!=1) { if (a[p] > a[p>>1]) { swap(a[p],a[p>>1]); p = p>>1; } else { break; } } } void pop()//删除最大值 { swap(a[1],a[n]);n--; int p=1; while ((p<<1) <= n) { int l=p<<1; int r=l|1;//p*2+1 int pp=l; if (r<=n && a[r] > a[l]) pp=r;//pp一定是两个儿子中较大的那个 if (a[pp] > a[p]) { swap(a[pp],a[p]); p=pp; } else { break; } } } int size()//询问还有几个数 { return n; } }; ``` ### 8.并查集: ```cpp #include<bits/stdc++.h> using namespace std; const int maxn=1e8; int to[maxn],n,p1,p2;//to[i] 代表i的箭头指向谁 int go(int p)//从p点出发 看最后会走到哪里 { if (p == to[p]) return p; else { to[p] = go(to[p]); return to[p]; } } int main() { cin >> n; for (int i=1;i<=n;i++) to[i] = i; //合并 to[go(p1)] = go(p2); //查询 go(p1) == go(p2); } ``` ## 下午 ### 9.trie(本质是树): 下一个节点是上面所有节点的和 如1-0-1-0 1010(10) -表示一条边 ```cpp struct node { int nxt[2];//nxt[0] nxt[1] 代表从当前点走0和1会走到哪里 走到0的话代表这个节点不存在 node() { nxt[0] = nxt[1] = 0; } }z[23333]; void insert(int x) { int p=root; for (int i=30;i>=0;i--) { int y=(x>>i)&1;//取出x二进制的第i位 if (z[p].nxt[y] == 0) {; cnt++; z[p].nxt[y] = cnt; } p = z[p].nxt[y]; } } int query(int x)//从trie中找一个数 使得他和x异或之后最大 { int p=root,ans=0; for (int i=30;i>=0;i--) { int y=(x>>i)&1; if (z[p].nxt[y^1] != 0) ans=ans|(1<<i),p=z[p].nxt[y^1]; else p=z[p].nxt[y]; } return ans; } int main() { root = 1; } ``` ### 10.莫队(≈暴力): ```cpp #include<bits/stdc++.h> using namespace std; const int maxn=1e5; int belong[maxn],cnt,ans; struct query { int l,r,id,ans; }q[maxn]; bool cmp1(const query &q1, const query &q2) { if (belong[q1.l] != belong[q2.l]) return belong[q1.l] < belong[q2.l]; else return q1.r < q2.r; } bool cmp2(const query &q1, const query &q2) { return q1.id < q2.id; } void ins(int x) { cnt [x] ++; if (cnt [x] % 2 == 0) ans++; else if (cnt [x] != 1) ans--; } void del(int x) { cnt [x] --; if (cnt[x] != 0) { if (cnt[x] % 2 == 0) ans++; else ans--; } } int main() { cin >> n >> m; for (int i=1;i<=n;i++) cin >> a[i]; for (int i=1;i<=m;i++) { cin >> q[i].l >> q[i].r; q[i].id = i; } int s = sqrt(n); for (int i=1;i<=n;i++) belong[i] = i/s+1; sort(q+1,q+m+1,cmp1); for (int i=q[1].l;i<=q[1].r;i++) ins(a[i]); q[1].ans = ans; for (int i=2;i<=m;i++)//O(Nsqrt(N)) { int l1=q[i-1].l,r1=q[i-1].r; int l2=q[i].l,r2=q[i].r; if (l1 < l2) for (int i=l1;i<l2;i++) del(a[i]); else for (int i=l2;i<l1;i++) ins(a[i]); if (r1 < r2) for (int i=r1+1;i<=r2;i++) ins(a[i]); else for (int i=r2+1;i<=r1;i++) del(a[i]); q[i].ans = ans; } sort(q+1,q+m+1,cmp2); for (int i=1;i<=m;i++) cout << q[i].ans << "\n"; return 0; } ``` ### 11.分块(≈分治) ```cpp #include<bits/stdc++.h> using namespace std; const int maxn=1e5; int n,m; int belong[maxn],a[maxn];//belong[i] 代表第i个数属于第几块 int sum[maxn];//sum[i] 代表第i块的和是多少 int daxiao[maxn];//daxiao[i] 代表第i块的大小是多少 int col[maxn];//col[i] 代表第i块被整体加了col[i] int main() { cin >> n >> m; for (int i=1;i<=n;i++) cin >> a[i]; int s = sqrt(n);//每块的大小 for (int i=1;i<=n;i++) belong[i] = i/s+1; for (int i=1;i<=n;i++) { sum[belong[i]] += a[i]; daxiao[belong[i]] ++; } for (int x=1;x<=m;x++) { int opt; cin >> opt; if (opt == 1)//询问操作 { int l,r; cin >> l >> r; int ans=0; if (belong[l] == belong[r]) for (int i=l;i<=r;i++) ans += a[i] + col[belong[i]]; else { for (int i=l;belong[i] == belong[l]; i++) ans += a[i] + col[belong[i]]; for (int i=r;belong[i] == belong[r]; i--) ans += a[i] + col[belong[i]]; for (int i=belong[l] + 1; i < belong[r]; i++) ans += sum[i]; } cout << ans << "\n"; } else { int l,r,v; cin >> l >> r >> v; if (belong[l] == belong[r]) for (int i=l;i<=r;i++) a[i] += v; else { for (int i=l;belong[i] == belong[l]; i++) a[i] += v,sum[belong[i]] += v; for (int i=r;belong[i] == belong[r]; i--) a[i] += v,sum[belong[i]] += v; for (int i=belong[l] + 1; i < belong[r]; i++) { sum[i] += v * daxiao[i]; col[i] += v; } } } } return 0; } ``` ### 12.merge ```cpp void merge(int l,int r)//要计算l~r这个区间有多少个逆序对 { if (l==r) return; int m=(l+r) >> 1;//(l+r)/2 merge(l,m);//递归去算l~m的答案 a[l]~a[m] 排好序了 merge(m+1,r);//递归去算m+1~r的答案 a[m+1]~a[r] 排好序了 //i在左边 j在右边的答案 int p1 = l, p2 = m+1; for (int i=l;i<=r;i++) { if (p1 > m) b[i] = a[p2],p2++; else if (p2 > r) b[i] = a[p1],p1++; else if (a[p1] <= a[p2]) b[i] = a[p1],p1++; else b[i] = a[p2],p2++,ans+=m-p1+1; } for (int i=l;i<=r;i++) a[i] = b[i]; } ``` ### 13.染色的暴力做法 ```cpp int main() { cin >> n; for (int i=1;i<=n;i++) to[i] = i; for (int i=m;i>=1;i--)//倒着读 自己实现 { int l,r,x; //go(i) 从i向右 第一个没被染色的位置 cin >> l >> r >> x;//第i个操作 int p = go(l); while (p<=r)//当前位置还在区间内 { a[p] = x;//染色 int np = go(p+1); to[p] = go(r+1); p = np; } } } ``` ### 14.杂论 #### 1.不能局限于考纲,出题人基本不管。 #### 2.如果数的顺序对于答案没有影响,那么先排序。 #### 3.基本位运算: #### x>>1 x÷2 #### x<<1 x*2 #### x<<y $x*(2^y)$ #### x>>y $x÷(2^y)$ #### x^y 把x和y转化为二进制,将两个数进行一位位地比对,相同为0,不同为1。 #### 4.题目正着做很难就反着做(正难则反)。 #### 5.如果没有进位或退位,可以考虑按位做。 ### 15.已完成作业: #### [P3378](https://www.luogu.com.cn/record/162875406) #### [P1886](https://www.luogu.com.cn/record/215612877) #### [P3372](https://www.luogu.com.cn/record/215613494)
Loading...
点赞
1
收藏
1