问题 D: 最大值
时间限制: 1 Sec 内存限制: 128 MB
[提交] [状态]
题目描述
给出N个整数,和一个长度值Len,要求在这N个整数中每个长度为Len的连续一段数中的最大值。
例如:N=8,Len=3,8个整数是:2 5 1 1 2 4 7 1。答案是 5 5 2 4 7 7 。
解释:
2 5 1的最大值是5
5 1 1的最大值是5
1 1 2的最大值是2
1 2 4的最大值是4
2 4 7的最大值是7
4 7 1的最大值是7
输入
第一行2个正整数:N,Len。N范围[2…100000],Len范围[2…N]
第二行:N个正整数,每个数范围[1…1000000000]。
输出
一行,N-Len+1个整数。
样例输入 Copy
4 3
7 2 1 4
样例输出 Copy
7 4
思路看第二个代码吧。还是说一下吧:简单来说就是单调栈思想;
用一个数组指区间值的下标(因为要求最大值也就是如果这个数大于这个数组的最后一位的话就替换下来,如果小于就把这个数存放到里面)。
我说的有点不明白参考一下人家说的吧:
插入:为了保证单调队列的递减性,我们在插入元素xx(struct x类型)的时候,要将队尾的元素和xx的a成员(表示该元素的数据)比较,如果队尾的元素不大于a,则删除队尾的元素,然后继续将新的队尾的元素与a比较,直到队尾的元素大于a,这个时候我们才将xx插入到队尾。
删除:由于我们只需要保存len个元素中的最大值,所以当队首的元素的下标小于等于i-len的时候,就说明队首的元素对于求最大值已经没有意义了。(注意不是每经过一个循环后就删除队首元素,而是要根据队首元素的下标来确定,因为有时单调队列中的元素不一定是len个)所以当index<=i-len时,将队首元素删除。
#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
using namespace std;
const int maxn=2e6+1010;
#define inf 0x3f3f3f3f
const int mod=1000000007;
const int MOD=10007;
inline int read() {
int x=0;
bool t=false;
char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
priority_queue<ll , vector<ll> , greater<ll> > mn;//上 小根堆 小到大
priority_queue<ll , vector<ll> , less<ll> > mx;//下 大根堆 大到小
map<ll,ll>mp;
ll n,m,t,l,r,p;
ll sum,ans,res,cnt,flag,maxx,minn;
bool isprime[maxn];
ll a[maxn],b[maxn],c[maxn];
ll dis[maxn],vis[maxn],head[maxn];
ll dp[1010][1010];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
flag=0;
cnt=-1;
for(int i=1;i<=m;i++)
{
for(;flag<=cnt&&a[i]>=a[dis[cnt]];cnt--);
dis[++cnt]=i;
}
cout<<a[dis[flag]]<<" ";
for(int i=m+1,j=1;i<=n;i++,j++){
if(flag<=cnt&&dis[flag]<=j) flag++;
for(;flag<=cnt&&a[i]>=a[dis[cnt]];cnt--);
dis[++cnt]=i;
cout<<a[dis[flag]]<<" ";
}
return 0;
}
代码二:
#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
using namespace std;
const int maxn=2e6+1010;
#define inf 0x3f3f3f3f
const int mod=1000000007;
const int MOD=10007;
inline int read() {
int x=0;
bool t=false;
char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
priority_queue<ll , vector<ll> , greater<ll> > mn;//上 小根堆 小到大
priority_queue<ll , vector<ll> , less<ll> > mx;//下 大根堆 大到小
map<ll,ll>mp;
ll n,m,t,l,r,p;
ll sum,ans,res,cnt,flag,maxx,minn;
bool isprime[maxn];
ll a[maxn],b[maxn],c[maxn];
ll dis[maxn],vis[maxn],head[maxn];
ll dp[1010][1010];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
flag=0;//标记 最大的下标
cnt=-1;//
for(int i=1;i<=m;i++)
{
for(;flag<=cnt&&a[i]>=a[dis[cnt]];cnt--);//最后一位变大或者不变 直接换下来
dis[++cnt]=i;// 变小 把这个数加进去
}
cout<<a[dis[flag]]<<" ";
for(int i=m+1,j=1;i<=n;i++,j++){
if(flag<=cnt&&dis[flag]<=j) flag++;//j来标记是否略过去这个数
cout<<"flag"<<" "<<flag<<endl;
for(;flag<=cnt&&a[i]>=a[dis[cnt]];cnt--);
dis[++cnt]=i;
cout<<"dis:";
for(int i=0;i<=cnt;i++)
cout<<dis[i]<<" ";
cout<<endl;
cout<<"max:"<<a[dis[flag]]<<" ";
cout<<endl;
}
return 0;
}