1.Priority Queue
此题为优先队列基础题,掌握即可,再按题中要求写代码,代码如下:
#include<iostream>
#include<queue>
#include<string>
using namespace std;
int main()
{
priority_queue<int> q;
int n;
string s;
string s1="insert";
string s2="extract";
string s3="end";
cin>>s;
while(s!=s3)
{
if(s==s1)
{
cin>>n;
q.push(n);
}
else if(s==s2)
{
cout<<q.top()<<endl;
q.pop();
}
cin>>s;
}
return 0;
}
2.ST 表 && RMQ 问题
此题为对ST表的应用,按照题目意思使用快速读入,对log_2进行预处理,后面就是ST表的操作,代码如下:
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int M=1e5+5;
int smax[M][31],log_2[M];
inline int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
int main()
{
int n,m;
n=read();
m=read();
log_2[1]=0;
for(int i=2;i<=n;i++)
{
log_2[i]=log_2[i/2]+1;
}
for(int i=1;i<=n;i++) smax[i][0]=read();
for(int j=1;j<=log_2[n];j++)
{
for(int i=1;i+(1<<j)-1<=n;i++)
{
smax[i][j]=max(smax[i][j-1],smax[i+(1<<(j-1))][j-1]);
}
}
int l,r;
for(int i=1;i<=m;i++)
{
l=read();
r=read();
int s=log_2[r-l+1];
printf("%d\n",max(smax[l][s],smax[r-(1<<s)+1][s]));
}
return 0;
}
3.合并果子
由题意不难知道,最优解为每次合并重量最小的两堆果子,则我们用优先队列解决此题,代码如下:
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
#define int long long
signed main()
{
int n,num;
int ans=0;
priority_queue<int,vector<int>,greater<int> > q;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>num;
q.push(num);
}
while(q.size()>1)
{
int t1=q.top();
q.pop();
int t2=q.top();
q.pop();
ans+=t1+t2;
q.push(t1+t2);
}
cout<<ans;
return 0;
}
4.约瑟夫问题
遇到环的问题我们把它链化,此题可用队列解,每次对编号进行检查,然后决定队首的去留,代码如下:
#include<iostream>
#include<queue>
using namespace std;
int main()
{
int n,m,num;
int k=0;
queue<int> q;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
q.push(i);
}
while(q.size()>0)
{
k++;
if(k==m)
{
cout<<q.front()<<" ";
q.pop();
k=0;
}
else
{
q.push(q.front());
q.pop();
}
}
return 0;
}
5.Look Up S
此题可用栈的方法来解,对每只牛编号在遍历,与栈头进行比较,若不为空栈且大于栈头身高,则找到栈头的仰望对象,进行记录,代码如下:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin>>n;
vector<int> h(n);
vector<int> re(n,0);
for(int i=0;i<n;i++) cin>>h[i];
stack<int> s;
for(int i=0;i<n;i++)
{
while(!s.empty()&&h[i]>h[s.top()])
{
re[s.top()]=i+1;
s.pop();
}
s.push(i);
}
for(int i=0;i<n;i++) cout<<re[i]<<endl;
return 0;
}
6.国旗计划
本题要计算每个战士必须参加时覆盖全部边境线所需最少战士数,由于边境线是环形,可将区间复制一份处理,即二倍链,采用倍增算法优化,通过预处理和跳跃计算减少遍历,降低时间复杂度,代码如下:
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
int n, m;
int ans[MAXN];
int f[MAXN * 2][20];
struct node {
int id;
int l, r;
} s[MAXN * 2];
bool cmp(node a, node b) {
return a.l < b.l;
}
void pre() {
for (int i = 1, p = 1; i <= 2 * n; i++) {
while (p <= 2 * n && s[p].l <= s[i].r) {
p++;
}
f[i][0] = p - 1;
}
for (int i = 1; i < 20; i++) {
for (int j = 1; j <= 2 * n; j++) {
f[j][i] = f[f[j][i - 1]][i - 1];
}
}
}
void solve(int k) {
int rr = s[k].l + m;
int tot = 1;
int p = k;
for (int i = 19; i >= 0; i--) {
if (f[k][i] != 0 && s[f[k][i]].r < rr) {
tot += (1 << i);
k = f[k][i];
}
}
ans[s[p].id] = tot + 1;
}
int main() {
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d %d", &s[i].l, &s[i].r);
if (s[i].r < s[i].l) {
s[i].r += m;
}
s[i].id = i;
}
sort(s + 1, s + 1 + n, cmp);
for (int i = 1; i <= n; i++) {
s[i + n] = s[i];
s[i + n].l = s[i].l + m;
s[i + n].r = s[i].r + m;
}
pre();
for (int i = 1; i <= n; i++) {
solve(i);
}
for (int i = 1; i <= n; i++) {
printf("%d ", ans[i]);
}
return 0;
}
心得体会:
通过本专题的学习,我对栈,队列,ST表有了一定的应用能力,六道题目有难有易,尤其是最后一道题,考虑的东西和使用的方法很多,值得我去深入探究,我也对后续学习充满信心。
827

被折叠的 条评论
为什么被折叠?



