灵能传输

题目

在这里插入图片描述

解析

这道题非常难想啊!!!!

首先要能想到用前缀和思考这个问题,对一个武士进行灵能传输对前缀和的影响就是交换两个前缀和,所求即求相邻前缀和差的最大值最小
往下要想怎么样的序列是所求的序列呢?我们只需要排个序即可,如果序列单调那么所求就是最小的

如果第一个点和最后一个点是可以移动的,那么这道题到这里就结束了,可惜只能移动中间的数,那么一个什么样子的序列是在考虑首尾点的情况下能得到最优解的呢?

只需要让序列中单调的部分最多,就是最优解了
先严格保证第一个数严格小于等于最后一个数,然后只需要保证序列中最小值更靠近第一个点,最大值更靠近最后一个点即可保证得到最优解序列,如下图所示:
在这里插入图片描述
最后排完序之后如何得到最终的序列呢?排序之后需要在第一段和第三段的位置隔一个点取一个点,第二段的位置取剩下的点即可得到最优解。这样取可以保证每一步的步长都是最短的,所以是最优解!

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 300010;
int n;
ll a[N], s[N];
bool st[N];
int main()
{
    
    
    int t;
    scanf("%d", &t);
    while (t--)
    {
    
    
        scanf("%d", &n);
        memset(s, 0, sizeof(s));
        for (int i = 1; i <= n; i++)
        {
    
    
            scanf("%lld", &a[i]);
            s[i]=s[i-1]+a[i];
        }
        ll s0=s[0],sn=s[n];
        if(s0>sn) swap(s0,sn);
        sort(s,s+1+n);
        for(int i=0;i<=n;i++)
        {
    
    
            if(s[i]==s0)
            {
    
    
                s0=i;
                break;
            }
        }
        for(int i=n;i>=0;i--)
        {
    
    
            if(s[i]==sn)
            {
    
    
                sn=i;
                break;
            }
        }
        memset(st,0,sizeof(st));
        int l=0,r=n;
        for(int i=s0;i>=0;i-=2)
        {
    
    
            a[l++]=s[i];
            st[i]=1;
        }
        for(int i=sn;i<=n;i+=2)
        {
    
    
            a[r--]=s[i];
            st[i]=1;
        }
        for(int i=0;i<=n;i++)
        {
    
    
            if(!st[i])
                a[l++]=s[i];
        }
        ll res=0;
        for(int i=1;i<=n;i++) res=max(res,abs(a[i]-a[i-1]));
        cout<<res<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_46126537/article/details/113354731