思维+二分。
读题,看见移动至最近最大值下意识想到单调栈,但是又发现这种移动需要若干次,时间复杂度太大,也没必要用单调栈。
思考发现题目要求找到借助魔法的最短排队时间,发现具有单调性(魔法用的越多排队时间越短或不变),考虑使用二分。
那么我们应该二分什么属性/参数?又以什么样的函数关系来衡量当前二分出来的值是否合适?这时候就需要一点点思维了:我们搓一些数据来手玩一下,不难发现猫猫在使用完魔法后可能还需要像寻常守规矩的猫猫一样等待前面的猫结账。因此,我们可以将猫猫的移动过程拆成两部分:会使用魔法的神奇猫猫(使用若干次魔法进行位置交换) 以及 老实排队的普通猫猫(等待前面的猫结账)。而猫猫最短排队时间其实就是老实排队的普通猫猫时间,因为使用魔法的时间会被包含在老实排队的普通猫猫时间中(可以这样理解:目标位置总排队等待时间=魔法转移时间+转移到目标位置后还需要等待的时间)
因此,我们可以二分使用魔法的次数,同时确保每一次使用魔法的时候猫猫都在队伍里(即确保猫猫不能离开队列却还在使用魔法)
二分出最大使用魔法次数后计算还需要老实排队的时间,此即为最小排队时间。
#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define fi first
#define se second
#define endl '\n'
// ---
using ll=long long;
using ull=unsigned long long;
// ---
template<class K,class V>
using umap=unordered_map<K,V>;
template<class T>
using max_heap=priority_queue<T>;
template<class T>
using min_heap=priority_queue<T,vector<T>,greater<T>>;
// ---
// 创建随机引擎
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
// 生成一个在 [l, r] 间的随机整数
int randint(int l, int r) {
uniform_int_distribution<int> dist(l, r);
return dist(rng);
}
// 生成一个 [0,1) 的随机实数
double randdbl() {
uniform_real_distribution<double> dist(0.0, 1.0);
return dist(rng);
}
// ---
const int INF=1e9;
const ll LINF=4e18;
const int mod=1e9+7;
const double eps=1e-9;
// ---
const int maxn=2e5+5;
int n,val;
int a[maxn];
stack<int> st;
bool check(int m)
{
int id,mm=m;
stack<int> tmp=st;
while(mm && tmp.size()!=0)
{
id=tmp.top();
tmp.pop();
--mm;
}
return id>=m; // 使用魔法时置换后的位置需要仍然在队伍中
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin>>n;
for(int i=1;i<=n;++i) cin>>a[i];
cin>>val;
for(int i=1;i<=n;++i)
{
if(a[i]>val) st.push(i);
}
int l=0,r=st.size(),mid;
while(l<r)
{
mid=((l+r+1)>>1);
if(check(mid))
l=mid;
else
r=mid-1;
}
int cnt=l,res=0; // res 为猫猫最后一次使用魔法到达的位置
while(cnt)
{
res=st.top();
st.pop();
--cnt;
}
int last; // 需要等待多久
if(res!=0)
last=res;
else
last=n+1;
cout<<last;
return 0;
}

京公网安备 11010502036488号