题面:
Bessie and Elsie are helping Farmer John wash the dishes, a more complicated process than one might think due to their lack of opposable thumbs.
The two cows decide that Bessie will apply soap, and Elsie will rinse. Bessie is given a dirty stack of plates labeled 1 through N (1≤N≤1e5) Elsie has an empty stack, where clean plates will go. There is a counter in between Bessie and Elsie for soapy stacks.
At each step, either:
Bessie takes a plate from the top of the dirty stack, applies soap, and then places it on the counter. When placing a soapy plate on the counter, Bessie must either (i) place the plate on top of an existing non-empty soapy stack or (i) create a new soapy stack to the right of all existing soapy stacks.
Elsie takes a plate from the top of the leftmost soapy stack. Elsie rinses the plate, then places it on top of the clean stack.
The goal is for the clean stack to have all plates in order, with the smallest label on the bottom and the largest label on the top. It may not be possible for the cows to achieve this goal for the entire stack of plates, so please determine the length of the largest prefix of the input ordering for which the goal is achievable.
INPUT
The first line of input contains N. The next N lines specify the order of the dishes in Bessie’s stack, with the first number being the dish on top of the stack.
OUTPUT
Please output the length of the longest prefix of the input stack that can be successfully washed so that the plates end up ordered properly in the clean stack.
sample:
5
4
5
2
3
1
4
思路:
二分右边界的最大值,对于每次check,可以是由栈来模拟。模拟的时候可以贪心,采取如下策略:
第一个数:创建第一个栈,把这个数入栈
当前的数大于所有之前的数:在最右边创建一个栈,把这个数入栈
其余:从左往右找到第一个栈底大于当前数字的栈,把栈中比它小的以及所有在左边的栈从左往右全部出栈,再把这个数字入栈。出栈时需要判断是否满足情况,其中找到栈可以使用二分来优化。
所有数字都入栈后,从左往右,一个栈一个栈地出栈,判断是否满足情况
参考代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int num[N];
int maxn[N];//记录栈底的数
int ls[N];
stack<int>st[N];
int findpos(int l,int r,int x){
return upper_bound(maxn+l,maxn+1+r,x)-maxn;
}
bool judge(int m){
int top=0,low=1;
st[++top].push(num[1]);
maxn[top]=num[1];
int now=0;
bool ff=true;
for(int i=2;i<=m;i++){
if(num[i]>maxn[top]){//情况二
st[++top].push(num[i]);
maxn[top]=num[i];
}
else{//情况三
int j=findpos(low,top,num[i]);//找到第一个栈底大于当前数的栈
if(maxn[j]>num[i]){
if(st[j].top()>num[i]){
st[j].push(num[i]);
}
else{
for(int k=low;k<j;k++){
while(!st[k].empty()){
int v=st[k].top();
st[k].pop();
if(v<now){
ff=false;
break;
}
now=v;
}
if(!ff)break;
low++;
}
while(st[j].top()<num[i]){
int v=st[j].top();
st[j].pop();
if(v<now){
ff=false;
break;
}
now=v;
}
if(num[i]<now){
ff=false;
break;
}
st[j].push(num[i]);
}
}
}
if(!ff)break;
}
if(ff){
for(int i=low;i<=top;i++){
while(!st[i].empty()){
int v=st[i].top();
st[i].pop();
if(v<now){
ff=false;
break;
}
else{
now=v;
}
}
if(!ff)break;
}
}
if(!ff){
for(int i=low;i<=top;i++){
while(!st[i].empty())st[i].pop();
}
}
return ff;
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&num[i]);
ls[i]=num[i];
}
sort(ls+1,ls+1+n);
int top=unique(ls+1,ls+1+n)-ls-1;
for(int i=1;i<=n;i++){//离散化
num[i]=lower_bound(ls+1,ls+1+top,num[i])-ls;
}
int l=1,r=n,mid,ans=1;
while(l<=r){
mid=(l+r)>>1;
if(judge(mid)){
ans=mid;
l=mid+1;
}
else{
r=mid-1;
}
}
printf("%d\n",ans);
return 0;
}