结构体排序:
题目:Aki的行程
cpp### 描述 Aki 记录了训练营的若干个活动时间段。每个时间段用两个整数l,r表示(包含端点),含义是从第l天到第r天都有活动。 为了做一个更清晰的日程表,Aki 想把有交集或首尾相接的时间段合并: - 若两个时间段[l₁, r₁]与[l₂, r₂]满足l₂ ≤ r₁ + 1(在按起点排序后),则它们可以合并为[l₁,max(r₁, r₂)]。 请输出合并后的所有时间段(按起点从小到大)。 --- ### 输入描述 第一行一个整数m,表示时间段数量。 接下来m行,每行两个整数l,r。 - \( 1 \leq M \leq 10^5 \) - \( 1 \leq L, R \leq 10^9 \) --- ### 输出描述 第一行输出合并后时间段的个数t。 接下来t行,每行输出一个合并后的时间段(按L从小到大)。 --- ### 用例输入 1 ``` 5 1 3 8 10 2 6 7 7 15 18 ``` ### 用例输出 1 ``` 2 1 10 15 18 ```代码:
cpp#include<bits/stdc++.h> using namespace std; const int N=1e5+10; typedef long long ll; ll m,sum,num; struct node{ ll l,r; }a[N],b[N]; bool cmp(node a,node b){ return a.l<b.l; } int main(){ cin>>m; for(int i=1;i<=m;i++){ cin>>a[i].l>>a[i].r; } sort(a+1,a+m+1,cmp); for(int i=1;i<=m-1;i++){ if(a[i+1].l<=a[i].r+1){ a[i+1].l=a[i].l; a[i+1].r=max(a[i].r,a[i+1].r); }else{ b[++num].l=a[i].l; b[num].r=a[i].r; sum++; } } b[++num].l=a[m].l; b[num].r=a[m].r; sum++; cout<<sum<<endl; for(int i=1;i<=sum;i++){ cout<<b[i].l<<' '<<b[i].r<<endl; } return 0; }
题目:Aki的活动选择
cpp### 描述 Aki 看到训练营里有很多活动,每个活动占用一个时间段 `[s_i, e_i]`(包含端点)。Aki 想参加尽可能多的活动,但同一时间只能参加一个活动。 如果 Aki 选择了一组活动,其编号依次为 `p₁,p₂,...`(按参加顺序),则需要满足: - 对任意相邻两个活动 `p_j,p_{j+1}`,有 `s_{p_{j+1}} ≥ e_{p_j}`。 请你输出 Aki 最多能参加多少个活动。 --- ### 输入描述 第一行一个整数 `n`,表示活动数量。 接下来 `n` 行,每行两个整数 `s_i, e_i`。 - \( 1 \leq n \leq 10^5 \) - \( 0 \leq s_i, e_i \leq 10^9 \) --- ### 输出描述 输出一个整数,表示最多能参加的活动数量。 --- ### 用例输入 1 ``` 6 1 3 3 5 0 2 5 6 2 4 6 7 ``` ### 用例输出 1 ``` 4 ```代码:
cpp#include<bits/stdc++.h> using namespace std; const int N=1e5+10; typedef long long ll; ll n,sum=1; struct node{ ll s,e; }a[N]; bool cmp(node a,node b){ if(a.e!=b.e)return a.e<b.e; return a.s<b.s; } int main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>a[i].s>>a[i].e; } sort(a+1,a+n+1,cmp); ll c=a[1].e; for(int i=1;i<=n-1;i++){ if(a[i+1].s>=c){ c=a[i+1].e; sum++; } } cout<<sum<<endl; return 0; } /* 0 2 1 3 2 4 3 5 5 6 6 7 */
双指针:
题目:子序列
cpp描述 给定一个长度为n的数组a,找出数组内最长且无重复元素的区间,输出其长度。 例如: n=5 a = {1 2 2 3 5} 最长无重复元素的区间的选择下标为[3,5],即选择第三个到第五个数,其区间长度为3。 输入描述 第一行一个正整数n,代表数组大小,n<=10 5第二行n个数,代表每个a[i],a[i]<=10^6 输出描述 一个数,代表无重复元素的最长区间长度。 用例输入 1 5 1 2 2 3 5 用例输出 1 3 用例输入 2 6 1 2 1 2 3 1 用例输出 2 3代码:
cpp#include<bits/stdc++.h> using namespace std; const int N=1e5+10; typedef long long ll; ll n,a[N],l=1,r=1,q,cnt,len; map<int,int> b; int main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; } for(r=1;r<=n;r++){ if(b[a[r]]){ while(b[a[r]]){ b[a[l]]=0; l++; } } len=max(len,r-l+1); b[a[r]]++; } cout<<len; return 0; }
单调栈:
题目:Aki和摩天大楼
cpp### 描述 Aki所在的城市里,有 N 座摩天大楼排成一排,从左到右编号为 1,2,...,N。 第 i 座大楼的高度为 A_i。 现在Aki想在这些大楼前搭建一个广告牌矩形,要求: - 广告牌覆盖一段连续的大楼区间 `[l, r]`(\(1 \leq l \leq r \leq N\)); - 广告牌的高度为一个正整数 `h`; - 为了不把大楼挡住,必须满足所有 \(i \in [l, r]\),都有 \(h \leq A_i\)。 也就是说,广告牌可以看作一个宽度为 \((r - l + 1)\)、高度为 \(h\) 的矩形,完全"贴"在大楼前面,并且不会超过任何一座大楼的高度。 Aki的目标是让广告牌的面积最大,面积定义为: \[ S = (r - l + 1) \times h \] 请你计算最大可能的广告牌面积。 --- ### 输入描述 第一行输入一个整数 \(N\)。 第二行输入 \(N\) 个整数 \(A_1, A_2, \dots, A_N\)。 - \(1 \leq N \leq 10^4\) - \(1 \leq A_i \leq 10^5\) --- ### 输出描述 输出一个整数,表示最大广告牌面积。 --- ### 用例输入 1 ``` 6 2 4 4 9 4 9 ``` ### 用例输出 1 ``` 20 ``` --- ### 提示 样例解释: 选择区间 \([2,6]\),广告牌高度取 \(h = 4\),则面积为 \((6 - 2 + 1) \times 4 = 20\)。 要不要我帮你写一个**C++实现的单调栈解法**,可以高效解决这个最大矩形面积问题?代码:
cpp#include<bits/stdc++.h> using namespace std; const int N=1e5+10; typedef long long ll; ll n,a[N],l[N],r[N],sum; int main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>a[i];//高度 } stack<ll> s; for(int i=n;i>=1;i--){ while(s.size() && a[s.top()]>=a[i])s.pop(); r[i]=!s.size()?n+1:s.top(); s.push(i); } while(s.size())s.pop(); for(int i=1;i<=n;i++){ while(s.size() && a[s.top()]>=a[i])s.pop(); l[i]=!s.size()?0:s.top(); s.push(i); } for(int i=1;i<=n;i++){ sum=max(sum,(r[i]-l[i]-1)*a[i]); //cout<<l[i]<<' '<<r[i]<<endl; } cout<<sum<<endl; return 0; }