[ABC388G] Simultaneous Kagamimochi 2

题目大意

详细题目传送门
给出 \(n\) 和长度为 \(n\) 的单调不降序列 \(a\)

多组询问对于每一个 \(l,r\),求出最多可以分出多少对 \(a_i,a_j\) 满足 \(2\cdot a_i\leq a_j\),每一个 \(a_i,a_j\) 不能重复使用。询问互相独立。

\(n,Q\leq2\cdot 10^5\)

思路

先考虑单组询问情况,即 E 题。发现二分出一个最大的 \(k\) 满足 \(\forall 2\cdot a_i\leq a_{r-k+i},i\in [l,l+k-1]\)

发现对于多组数据的情况瓶颈在于判断 \(k\) 是否可行的 \(O(n)\) 时间复杂度。发现这些 \(a_i\) 的对应点是具有单调性的,所以我们 \(O(n)\) 找到对于每一个 \(a_i\)\(\max(j)\) 满足 \(2\cdot a_j\leq a_i\)。设 \(b_i=i-\max(j)\)。则上式就可以转化成 \(l+\max(b_{r-k+1},\cdots,b_{r})\stackrel{?}{<}r-k\)。用 ST 表维护区间 \(b_i\) 最大值即可。

时间复杂度 \(O(n\log n +Q\log n)\)

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MAXN=2e5+5;
ll n,a[MAXN];
ll st[MAXN][20],lg[MAXN];
ll query(ll l,ll r){
    ll g=lg[r-l+1];
    return max(st[l][g],st[r-(1<<g)+1][g]);
}
bool check(ll l,ll r,ll k){
    return l+query(r-k+1,r)<=r-k+1;
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin>>n;
	for(int i=2;i<=n+3;++i){
	    lg[i]=lg[i-1]+(i==(1<<(lg[i-1]+1)));
	}
	ll j=1;
	for(int i=1;i<=n;++i){
	    cin>>a[i];
	    while(j<i&&a[j]*2<=a[i]){
	        ++j;
	    }
	    st[i][0]=i-j+1;
	}
	for(int j=1;j<=lg[n];++j){
	    for(int i=1;i+(1<<j)-1<=n;++i){
	        st[i][j]=max(st[i][j-1],st[i+(1<<j-1)][j-1]);
	    }
	}
	
	ll Q;
	cin>>Q;
	while(Q--){
	    ll l,r;
	    cin>>l>>r;
	    ll L=0,R=(r-l+1)/2,ans=0;
	    while(L<=R){
	        ll mid=(L+R)>>1;
	        if(check(l,r,mid)){
	            ans=mid;
	            L=mid+1;
	        }else{
	            R=mid-1;
	        }
	    }
	    cout<<ans<<endl;
	}
	return 0;
}
posted @   tanghg  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 推荐几款开源且免费的 .NET MAUI 组件库
· 实操Deepseek接入个人知识库
· 易语言 —— 开山篇
· Trae初体验
点击右上角即可分享
微信分享提示