单调队列练习题(oj p1157 p1158 p1159)

本文分享了三道NOIP题目(P1157、P1158、P1159)的解题思路及代码实现,涉及单调队列、优先队列等数据结构,展示了算法设计与实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

p1157是很气人的...自从评测机挂了后,速度就特别慢,cin已经过不了了,然而我不知道,就各种**的提交

惨兮兮惨兮兮,这还是开了小号(通过率堪忧.jpg...)...

 

思路就是单调队列维护,用队列存储k个数中最小数下标......还是代码加注释好懂

 

#include <bits/stdc++.h>
using namespace std;
int n,k;
int qm[1000006],tail=1,head=1;
int a[1000006];
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
qm[head]=1;
for(int i=2;i<=k;i++)
{
while(a[i]<a[qm[tail]]&&tail>=head)//维护单调递减,在k个数内,如果当前元素有小于队尾元素(队列中下标对应原数组中的数)
tail--;//出队
qm[++tail]=i;//入队
}
for(int i=k;i<=n;i++)
{
if(i-qm[head]==k)//如果i-队头元素下标==k,证明该换最小值了,就head++;
head++;
while(a[i]<a[qm[tail]]&&tail>=head)//同上
tail--;
qm[++tail]=i;
cout<<a[qm[head]]<<' ';
}
cout<<endl;
head=1;tail=1;
qm[head]=1;
for(int i=2;i<=k;i++)//同上,以下维护单调递增
{
while(a[i]>a[qm[tail]]&&tail>=head)
tail--;
qm[++tail]=i;
}
for(int i=k;i<=n;i++)
{
if(i-qm[head]==k)
head++;
while(a[i]>a[qm[tail]]&&tail>=head)
tail--;
qm[++tail]=i;
cout<<a[qm[head]]<<' ';
}
return 0;
}

 P1158

合并果子

往年的一道noip题,思路还行...然而我被卡了差不多2天,本来想的思路对的,不知道怎么就想偏了。

总之就是没回从队中抽出最小的两个相加,出队,再将他们的和进队。说实话,如果不用STL,差不多就是一次一排序?或是二重?反正我没想出来....STL优先队列就很方便了

设一个小的优先级的队列,将最小的两个出队,在将他们的和进队。因为是n堆果子合并,所以实际只需合并n-1次

#include <bits/stdc++.h>
using namespace std;
struct cmp1
{
bool operator ()(int x, int y)
{
return x > y;//小的优先级高
}
};
priority_queue<int,vector<int>,cmp1>q;
int n,a,ans=0;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a;
q.push(a);
}
for(int i=1;i<=n-1;i++)
{
int x,y;
x=q.top();
q.pop();
y=q.top();
q.pop();
q.push(x+y);
ans+=x+y;
}
cout<<ans<<endl;
return 0;
}

 

P1159 假日

usaco原题。。。感觉我现在想不到算法,决定学完dp再回来补敲

转载于:https://www.cnblogs.com/ywjblog/p/7906371.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值