传送门:51nod 1272
题目大意:从一组数中找出一对数,满足左边的数小于等于右边的数,求两数的最大距离。
思路:
1.单调栈,建议学习一下单调栈的应用:单调栈原理及应用。理论上时间复杂度为O(n),但是实际没贪心快……并且最后一组会超时……迷思。不过还是给出单调栈的代码,大体思路是用一个单调递增栈处理,并用一个普通栈存储每次不能使栈单调的被弹出的元素。注意,我这里单调栈存储的是下标。
2.贪心。先将数据记录位置和值,并从大到小排序。然后从小到大插入每个数,这样插入的数就保证了后面的比前面的大,而只需要记录出现的位置最小值,每次插入的时候记录当前的位置和最小位置之差的最大值就可以了。注意,如果两个元素值相同时要按照位置从小到大排序,否则会出错。
代码:
单调栈(会超时):
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<stack>
using namespace std;
int main()
{
int i,n,mx,top,a[50010];
stack<int> st1,st2;
scanf("%d",&n);
mx=0;
for(i=0;i<n;i++) scanf("%d",&a[i]);
for(i=0;i<n;i++)
{
//如果单调栈为空或当前元素大于栈顶元素则入栈
if(st1.empty()||a[i]<a[st1.top()]) st1.push(i);
else
{
while(!st1.empty()&&a[i]>=a[st1.top()])
{ //如果栈非空并且当前元素>=栈顶元素则将栈顶元素出栈
top=st1.top(); //栈顶元素
st2.push(top); //保存到 st2 普通栈
st1.pop();
if(i-top>mx) mx=i-top; //记录最大距离
}
st1.push(i); //将当前元素入栈
while(!st2.empty())
{ //将普通栈中的元素再转移回单调栈
top=st2.top();
st1.push(top);
st2.pop();
}
}
}
printf("%d\n",mx);
return 0;
}
贪心:
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
struct node
{
int pos,val;
} a[50010];
int cmp(node x,node y)
{ //如果值相同按位置升序排列,否则按值升序排列
if(x.val==y.val) return x.pos<y.pos;
else return x.val<y.val;
}
int main()
{
int i,n,l,ans;
scanf("%d",&n);
ans=0;
for(i=0;i<n;i++)
{
scanf("%d",&a[i].val);
a[i].pos=i; //记录位置
}
sort(a,a+n,cmp); //排序
ans=0;
l=0x3f3f3f3f;
for(i=0;i<n;i++)
{ //插入每个元素
if(a[i].pos<l) l=a[i].pos; //记录最小位置
if(a[i].pos-l>ans) ans=a[i].pos-l; //记录最大距离
}
printf("%d\n",ans);
return 0;
}