P1440 求m区间内的最小值(单调队列)

这篇博客介绍了一种利用单调队列优化的筛数算法,通过在O(n)的时间复杂度内筛选出给定长度m内的最小整数,并在过程中实时输出。代码示例展示了如何维护队列的单调性并确保筛选出的数满足条件。

题意:
在这里插入图片描述
思路:用单调队列去不断进行筛数操作,O(n)扫一遍,两个while第一个while是使队列是单调的,如果不符合就弹数,第二个while是使队列里的元素要满足前m个。

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e6+100;
int a[maxn];
deque<int >m1;
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    printf("%d\n",0);
    for(int i=1;i<n;i++){
        scanf("%d",&a[i]);
        while(m1.size()&&a[m1.back()]>a[i]){
            m1.pop_back();
        }
        m1.push_back(i);
        while(i-m>=m1.front()){
            m1.pop_front();
        }
        printf("%d\n",a[m1.front()]);
    }
    return 0;
}

对于这道题目和这个代码,请你为我解释一下为什么要使用滑动窗口以及倍增状态的的定义,并为代码加上详细的注释: 代码: #include #include #include #include #define R register #define MAXN 1000010 typedef long long ll; using namespace std; ll n,k,m; ll p[MAXN]; ll f[MAXN],ff[MAXN],ans[MAXN]; int main() { scanf(“%lld%lld%lld”,&n,&k,&m); for(R ll i=1;i<=n;i++) { scanf(“%lld”,&p[i]); } f[1]=k+1; ll l=1,r=k+1; for(R ll i=2;i<=n;i++)//滑窗维护左右端点 { while(r+1<=n&&p[i]-p[l]>p[r+1]-p[i]) l++,r++; if(p[i]-p[l]>=p[r]-p[i]) f[i]=l; else f[i]=r; } for(R ll i=1;i<=n;i++) ans[i]=i;//初始跳0次 while(m)//倍增 { if(m&1) for(R ll i=1;i<=n;i++) ans[i]=f[ans[i]];//更新答案 m>>=1; memcpy(ff,f,sizeof(ff)); for(R ll i=1;i<=n;i++) f[i]=ff[ff[i]];//更新下一个跳到的点 } for(R ll i=1;i<=n;i++) printf("%lld ",ans[i]); return 0; } 题面: # P3509 [POI 2010] ZAB-Frog ## 题目描述 在一个特别长且笔直的 Byteotian 小溪的河床上,有 $n$ 块石头露出水面。它们距离小溪源头的距离分别为 $p_1 < p_2 < \cdots < p_n$。一只小青蛙正坐在其中一块石头上,准备开始它的跳跃训练。每次青蛙跳跃到距离它所在石头第 $k$ 近的石头上。具体来说,如果青蛙坐在位置 $p_i$ 的石头上,那么它将跳到这样的 $p_j$ 上,使得: $$ |\{ p_a : |p _ a - p _ i| < |p_j - p_i| \}| \le k \text{ and } |\{ p_a : |p _ a - p _ i| \le |p_j - p_i| \}| > k $$ 如果 $p_j$ 不是唯一的,那么青蛙在其中选择距离源头最近的石头。对于每一块石头分别计算,若青蛙从这块石头开始跳跃,经过 $m$ 次跳跃后最终会停留在哪一块石头上? ## 输入格式 标准输入的第一行包含三个整数 $n$、$k$ 和 $m$($1 \le k < n \le 1\,000\,000, 1 \le m \le 10^{18}$),用空格分隔,分别表示石头的数量、参数 $k$ 和计划跳跃的次数。第二行包含 $n$ 个整数 $p_j$($1 \le p_1 < p_2 < \cdots < p_n \le 10^{18}$),用空格分隔,表示小溪河床上连续石头的位置。 ## 输出格式 你的程序应在标准输出上打印一行,包含 $n$ 个整数 $r_1, r_2, \cdots, r_n$,用空格分隔。数字 $r_i$ 表示从输入顺序中的第 $i$ 块石头开始跳跃 $m$ 次后,青蛙最终停留的石头编号。 ## 输入输出样例 #1 ### 输入 #1 ``` 5 2 4 1 2 4 7 10 ``` ### 输出 #1 ``` 1 1 3 1 1 ``` ## 说明/提示 ### 样例 #1 解释: ![](https://cdn.luogu.com.cn/upload/image_hosting/yyilx2mp.png) 图中展示了青蛙从每块石头跳跃(单次跳跃)到的位置。 题面翻译由 ChatGPT-4o 提供。 提示: 1.预处理出每个点跳到离自己第k的点的编号,可以用一个类似滑动窗口的单调队列实现,具体见代码。不会的可以看看这道题 P1886 滑动窗口。 2.用倍增处理出每个点跳m次达到的点,即为答案。
10-02
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值