[题解]AT_abc263_d [ABC263D] Left Right Operation
思路
首先,不难发现最终的序列一定是形如下面的序列:
那么,我们就可以将其分为三段,每段都单独维护。
首先,对于第一段,我们可以枚举出最后一个 的位置 ,那么和为 。
对于第二段显然可以用前缀和维护,但是有一个问题,我们还不知道这一段的末尾位置在哪里。换而言之,我们需要确定 的起始位置。
那么,对于每一个位置 ,我们都可以 查询出将 全都修改为 能够使序列变小多少,记作 。
因此,我们可以用一个 pair
数组 维护 的后缀最大值,那么 mx.fst
记录的是后缀最大值的值,ms.snd
记录的是后缀最大值的位置。
那么,要想使答案最小,我们在枚举 时,就要是 对答案的贡献小,即选择一个位置 使得 最大,那么,这个操作,我们可以直接使用 来查询。
最后所有求出的值,取 即可。
Code
#include <bits/stdc++.h>
#define int long long
#define fst first
#define snd second
#define re register
using namespace std;
typedef pair<int,int> pii;
const int N = 2e5 + 10,inf = 1e18 + 10;
int n,x,y,ans = inf;
int arr[N],sp[N],sn[N];//sp 为前缀和,sn 为后缀和
pii mx[N];
inline int read(){
int r = 0,w = 1;
char c = getchar();
while (c < '0' || c > '9'){
if (c == '-') w = -1;
c = getchar();
}
while (c >= '0' && c <= '9'){
r = (r << 3) + (r << 1) + (c ^ 48);
c = getchar();
}
return r * w;
}
signed main(){
n = read();
x = read();
y = read();
for (re int i = 1;i <= n;i++){
arr[i] = read();
sp[i] = sp[i - 1] + arr[i];
}
for (re int i = n;i;i--) sn[i] = sn[i + 1] + arr[i];
mx[n + 1] = {0,n + 1};
for (re int i = n;i;i--){
int t = sn[i] - (n - i + 1) * y;
if (mx[i + 1].fst < t) mx[i] = {t,i};
else mx[i] = mx[i + 1];
}
for (re int i = 0;i <= n;i++){
int id = mx[i + 1].snd;
int sum = sp[id - 1] - sp[i] + i * x + (n - id + 1) * y;
ans = min(ans,sum);
}
printf("%lld",ans);
return 0;
}
作者:WaterSun
出处:https://www.cnblogs.com/WaterSun/p/18262007
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
分类:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】