题目链接
题目解法
我们先考虑什么样的序列 \(x_1,...,x_n\) 是可以被得到的
对于 \(x_i>x_{i+1}\) 的位置,我们需要至少对前缀 \([1,i]\) 做 \(x_i-x_{i+1}\) 次操作;对于 \(x_{i-1}<x_{i}\) 的位置,我们需要至少对后缀 \([i,n]\) 做 \(x_i-x_{i-1}\) 次操作
我们需要最大利用这个性质,所以我们从后往前依次做前缀操作,再从前往后依次做后缀操作,这样操作完之后会得到 \(x_i\) 全部相同的序列,则当前序列合法的条件是操作完后序列中的数 \(\ge 0\)
形式化表示一下为:\(x_1-\sum\limits_{i=1}^{n-1}[x_i>x_{i+1}](x_i-x_{i+1})\ge 0\)(或 \(x_n-\sum\limits_{i=1}^{n-1}[x_i<x_{i+1}](x_{i+1}-x_i)\ge 0\),这两个式子是等价的)
令 \(x_0=x_{n+1}=inf\)
即条件为 \(\sum\limits_{i=0}^{n}|x_i-x_{i+1}|\le 2\times inf\)(就是把上面的限制翻一倍)
我们考虑在原来的序列上单点加,使其满足条件,要求最小化序列和
可以发现,将满足 \(\max\limits_{i=l}^r\{x_i\}<\min\{x_{l-1},x_{r+1}\}\) 的 \([l,r]\) 全部 \(+1\),可以使左式的值 \(-2\)
用这个思路,我们考虑建出笛卡尔树,只要按照区间长度从小往大贪心做即可
时间复杂度 \(O(n\log n)\)
#include <bits/stdc++.h>
#define F(i,x,y) for(int i=(x);i<=(y);i++)
#define DF(i,x,y) for(int i=(x);i>=(y);i--)
#define ms(x,y) memset(x,y,sizeof(x))
#define SZ(x) (int)x.size()-1
#define all(x) x.begin(),x.end()
#define pb push_back
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
typedef pair<int,int> pii;
template<typename T> void chkmax(T &x,T y){ x=max(x,y);}
template<typename T> void chkmin(T &x,T y){ x=min(x,y);}
template<typename T> void read(T &FF){
FF=0;int RR=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
FF*=RR;
}
const int N=1000010;
const LL inf=1e17;
int n,L[N],R[N];
LL a[N];
pii seq[N];
int stk[N],top;
void work(){
read(n);
F(i,1,n) read(a[i]);
a[0]=a[n+1]=inf;
LL tot=0;F(i,0,n) tot+=abs(a[i]-a[i+1]);
stk[top=0]=-1;
F(i,0,n+1){
while(top&&a[i]>=a[stk[top]]) top--;
L[i]=stk[top]+1,stk[++top]=i;
}
stk[top=0]=n+2;
DF(i,n+1,0){
while(top&&a[i]>a[stk[top]]) top--;
R[i]=stk[top]-1,stk[++top]=i;
}
int cnt=0;
F(i,1,n){
if(L[i]==1&&R[i]==n) continue;
if(L[i]>1&&(R[i]==n||R[L[i]-1]==R[i])) seq[++cnt]={R[i]-L[i]+1,a[L[i]-1]-a[i]};
else seq[++cnt]={R[i]-L[i]+1,a[R[i]+1]-a[i]};
}
sort(seq+1,seq+cnt+1);
LL ans=0;
F(i,1,cnt){
if(tot<=2*inf) break;
auto [x,y]=seq[i];
if(tot-2*y<=2*inf) ans+=((tot-2*inf)/2)*x,tot=2*inf;
else ans+=1ll*x*y,tot-=2*y;
}
F(i,1,n) ans+=a[i];
printf("%lld\n",ans);
}
int main(){
int T;read(T);
while(T--) work();
return 0;
}
标签:cnt,ch,题解,top,Add,stk,qoj8542,序列,define
From: https://www.cnblogs.com/Farmer-djx/p/18262482