题解:P12646 [KOI 2024 Round 1] 升序
A 掉这道题才发现自己是第 9 个 A 的,抓紧来发篇题解。
题目传送门
[KOI 2024 Round 1] 升序
题意理解
一看到这道题,我发现其实就是 [KOI 2024 Round 1] 加倍 的加强版,多了一个区间查询。
题意:给你一个长度为
解题思路
简化一下,对于
举个例子,序列
思考一下,发现需要计算每个
But,序列
综上,我们可以归纳出,
考虑优化,将
对于
如何实现呢?我们知道,如果
代码实现
每次出现负数,原数组该位置的值至少
复杂度大约是
#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=3e5+10;
int n,q,a[N],c[N],sum,cnt,s[N],ss[N],nxt[N];
stack<int> st;
int getsum(int l,int r){
return (r+1)*(s[r]-s[l-1])-(ss[r]-ss[l-1]);
}
void zj(){
//预处理nxt[i]
for(int i=n;i>=0;i--){
while(!st.empty()&&s[st.top()]>=s[i]) st.pop();
if(!st.empty()) nxt[i]=st.top();
else nxt[i]=n+1;
st.push(i);
}
while(q--){
int l,r,ans=0;
cin>>l>>r;
if(l==r){
cout<<0<<endl;
continue;
}
int i=l-1;
while(i<r){
ans+=getsum(i+1,min(nxt[i]-1,r-1));//计算每一段的和
i=nxt[i];//跳到下一段
}
cout<<ans<<endl;
}
}
signed main(){
cin.tie(0)->ios::sync_with_stdio(0);
cin>>n>>q;
for(int i=1;i<=n;i++) cin>>a[i];
//计算 c[i]
for(int i=1;i<n;i++){
if(a[i+1]>a[i]){
int x=a[i];
while(x*2<=a[i+1]){
x*=2;
c[i]--;
}
}else{
int x=a[i+1];
while(x<a[i]){
x*=2;
c[i]++;
}
}
}
for(int i=1;i<=n;i++) s[i]=s[i-1]+c[i];//s[i]就是题解中的R[i]
for(int i=1;i<=n;i++) ss[i]=ss[i-1]+c[i]*i;
zj();
return 0;
}
写在最后
感谢 sheryang 提供的思路,谢谢观看,管理大大辛苦啦!