省选模拟 序列
题面
给定一个长度为 的序列 ,可以进行无限次下列操作:
对于 ,依次执行(而不是择一执行)
求最小的
思路
考虑一次操作对于序列前缀和的影响,对于 ,其前缀和为 ,一次操作后原序列变为 ,其前缀和变为 ,相当于对于任意连续的三个元素做一次操作,等价于前两个元素前缀和互换。而我们又知道,对于一个数列,相邻元素交换,最终可以构成任何这些元素的排列。因此题目转化为:重新排列前缀和数组 的 区间(由上述推论可知 永远不会被交换),使得 两两元素之差尽可能小(包括 与 之差和 与 之差)。
可以构造出最优排列方案:
-
第Ⅰ段:取所有小于 的 ,逐渐递减再递增,具体实现即为从大到小依次左边放一个右边放一个直至放完(参见注意事项)
-
第Ⅱ段:取所有大于等于 小于 的 ,直接从小到大排列
-
第Ⅲ段:取所有剩下的大于 的 ,逐渐递增再递减,具体实现即为从小到大依次右边放一个左边放一个直至放完
参见示意图:
具体证明:
对于Ⅱ段,显然顺序排列最优
对于Ⅰ、Ⅲ段:
- 若交换对象在同一递增/递减区间,交换后打破了单调性,差值只会变高,不优
- 若交换对象在不同单调性区间,交换后即使未打破单调性,也造成一边差值更小一边差值更大的不平衡情况,不优
注意事项
-
需要注意判断Ⅰ段与Ⅲ段长度的奇偶,处理落单的数
-
第Ⅰ段开头需要与 做差而结尾需要与后面大于 的数做差,为使答案最优,应该从大到小从左边开始左右依次放,反之第Ⅲ段需要从小到大从右边开始
-
为负时,为了方便处理,需要将 全部取反,由于答案是绝对值,因此不影响答案
代码
#include<bits/stdc++.h>
using namespace std;
template<class T>inline void rd(T &x){
T res=0,f=1;
char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1; ch=getchar();}
while(isdigit(ch)){res=res*10+ch-'0';ch=getchar();}
x=res*f;
}
template<class T>inline void wt(T x){
if(x<0){x=-x;putchar('-');}
if(x>9) wt(x/10);
putchar(x%10+'0');
}
const int MAXN=3e5+5;
typedef long long LL;
int n,a[MAXN];
LL pre[MAXN],ans[MAXN];
vector<LL>v1,v2,v3;
int main(){
int t;
rd(t);
while(t--){
pre[0]=0;ans[0]=0;
v1.clear();v2.clear();v3.clear();
rd(n);
for(int i=1;i<=n;i++){
rd(a[i]);
pre[i]=pre[i-1]+a[i];
}
if(pre[n]<0){
for(int i=1;i<=n;i++){
pre[i]=-pre[i];
}
}
for(int i=1;i<n;i++){
if(pre[i]<0) v1.push_back(pre[i]);
else if(pre[i]<pre[n]) v2.push_back(pre[i]);
else v3.push_back(pre[i]);
}
sort(v1.begin(),v1.end(),greater<LL>());
sort(v2.begin(),v2.end());
sort(v3.begin(),v3.end());
int l=1,r=v1.size();
for(int i=0;i<v1.size() && l<r;){
ans[r]=v1[i];r--,i++;
ans[l]=v1[i];l++,i++;
}
if(l==r){//v1长度为奇数
ans[l]=v1[v1.size()-1];
}
for(int i=0;i<v2.size();i++){
ans[v1.size()+1+i]=v2[i];
}
l=1,r=v3.size();
for(int i=0;i<v3.size() && l<r;){
ans[v1.size()+v2.size()+l]=v3[i];l++,i++;
ans[v1.size()+v2.size()+r]=v3[i];r--,i++;
}
if(l==r){//v3长度为奇数
ans[v1.size()+v2.size()+l]=v3[v3.size()-1];
}
ans[n]=pre[n];
LL maxx=-1e10;
for(int i=1;i<=n;i++){
maxx=max(maxx,abs(ans[i]-ans[i-1]));
}
wt(maxx);
putchar('\n');
}
return 0;
}
启示
遇到对序列比较复杂、涉及多个元素的操作时,可以尝试研究操作对于序列前缀和、差分等的影响,将操作的影响简化,由此找到更优异的性质。
本文作者:MessageBoxA
本文链接:https://www.cnblogs.com/SkyNet-PKN/p/18035150
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步