灵能传输

82 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 6 天,点击查看活动详情

[蓝桥杯 2019 省 B] 灵能传输

题目背景

在游戏《星际争霸 II》中,高阶圣堂武士作为星灵的重要 AOE 单位,在游戏的中后期发挥着重要的作用,其技能“灵能风暴”可以消耗大量的灵能对一片区域内的敌军造成毁灭性的伤害。经常用于对抗人类的生化部队和虫族的刺蛇飞龙等低血量单位

题目描述

你控制着 nn 名高阶圣堂武士,方便起见标为 1,2,,n1,2, \cdots,n。每名高阶圣堂武士需要一定的灵能来战斗,每个人有一个灵能值 aia_i 表示其拥有的灵能的多少(aia_i 非负表示这名高阶圣堂武士比在最佳状态下多余了 aia_i 点灵能,aia_i 为负则表示这名高阶圣堂武士还需要 ai-a_i 点灵能才能到达最佳战斗状态)。现在系统赋予了你的高阶圣堂武士一个能力,传递灵能,每次你可以选择一个 i[2,n1]i \in[2,n-1],若 ai0a_i \ge 0 则其两旁的高阶圣堂武士,也就是 i1i-1i+1i+1 这两名高阶圣堂武士会从 ii 这名高阶圣堂武士这里各抽取 aia_i 点灵能;若 ai<0a_i<0 则其两旁的高阶圣堂武士,也就是 i1,i+1i-1,i+1 这两名高阶圣堂武士会给 ii 这名高阶圣堂武士 ai-a_i 点灵能。形式化来讲就是 (ai1,ai,ai+1)(ai1+ai,ai,ai+1+ai)(a_{i-1},a_i,a_{i+1})\leftarrow (a_{i-1}+a_i,-a_i,a_{i+1}+a_i)

灵能是非常高效的作战工具,同时也非常危险且不稳定,一位高阶圣堂武士拥有的灵能过多或者过少都不好,定义一组高阶圣堂武士的不稳定度为 maxi=1n{ai}\max\limits_{i=1}^n\{|a_i|\},请你通过不限次数的传递灵能操作使得你控制的这一组高阶圣堂武士的不稳定度最小。

输入格式

本题包含多组询问。输入的第一行包含一个正整数 TT 表示询问组数。

接下来依次输入每一组询问。

每组询问的第一行包含一个正整数 nn,表示高阶圣堂武士的数量。

接下来一行包含 nn 个数 a1,a2,,ana_1,a_2, \cdots,a_n

输出格式

输出 TT 行。每行一个整数依次表示每组询问的答案。

样例 #1

样例输入 #1

3 3
5 -2 3
4
0 0 0 0
3
1 2 3

样例输出 #1

3 0 3

样例 #2

样例输入 #2

3 4
-1 -2 -3 7
4
2 3 4 -8
5
-1 -1 6 -1 -1

样例输出 #2

5 7 4

样例 #3

样例输入 #3

见文件trans3.in。

样例输出 #3

见文件trans3.ans

提示

【样例说明】

对于第一组询问:

22 号高阶圣堂武士进行传输操作后 a1=3a_1=3a2=2a_2=2a3=1a_3=1。答案为 33

对于第二组询问:

这一组高阶圣堂武士拥有的灵能都正好可以让他们达到最佳战斗状态。

【数据规模与约定】

对于所有评测用例,T3T \le 33n3×1053 \le n \le 3\times10^5ai109|a_i| \le 10^9

评测时将使用 2525 个评测用例测试你的程序,每个评测用例的限制如下:

蓝桥杯 2019 年省赛 B 组 J 题。

分析

这道题是个很难的题,难点1要想到用前缀和,难点2知道题目的本质是要交换前缀和,然后排序,求出!

代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <map>
#include <set>
#include <iomanip>
#include <cmath>
#include <unordered_map>
#include <stack>
#include <queue>
#define ll long long
#define lowbit(x) x&(-x)
using namespace std;
typedef pair<int,int> PII;
typedef pair<string,int> PSI;
int gcd(int x,int y){
    return y?gcd(y,x%y):x;
}
ll qmi(ll x,ll y,int mod){
    ll res=1;
    while(y){
        if(y&1) res=res*x%mod;
        y>>=1;
        x=x*x%mod;
    }
    return res;
}
const int N=300010;
int t,n;
ll s[N],a[N];
bool st[N];
inline void solve(){
    cin>>n;
    s[0]=0;
    memset(st,0,sizeof st);
    memset(a,0,sizeof a);
    for(int i=1;i<=n;i++){
        cin>>s[i];
        s[i]+=s[i-1];
        //cout<<s[i]<<" ";
    }
    ll s0=s[0],sn=s[n];
    sort(s,s+n+1);
    if(s0>sn) swap(s0,sn);
    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;
        }
    }
   
    int l=0,r=n;
    for(int i=s0;i>=0;i-=2){
        a[l++]=s[i];
        st[i]=true;
    }
    for(int i=sn;i<=n;i+=2){
        a[r--]=s[i];
        st[i]=true;
    }
    for(int i=0;i<=n;i++){
        if(!st[i]){
            a[l++]=s[i];
            st[i]=true;
        }
    }
    ll res=0;
    for(int i=1;i<=n;i++){
        //cout<<abs(s[i]-s[i-1])<<" ";
        res=max(res,abs(a[i]-a[i-1]));
    }
    cout<<res<<"\n";
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

希望能帮助到大家,QAQ