[CCPC 2024 Shandong I] 分割序列题解

题目描述

给定长度为 n 的整数序列 a1​,a2​,⋯,an​,请将序列分成 k 段连续且非空的子数组,使得序列中的每个元素恰属于一个子数组。令 si​ 表示从左到右第 i 个子数组里的元素之和,对于每个 1≤k≤n,求下式的最大值。

i=1∑k​i×si​

更正式地,对于每个 1≤k≤n,令 r0​=0 以及 rk​=n,您需要找到 (k−1) 个整数 r1​,r2​,⋯,rk−1​ 满足 r0​<r1​<r2​<⋯<rk−1​<rk​,并最大化下式的值。

i=1∑k​i×(j=ri−1​+1∑ri​​aj​)

输入格式

有多组测试数据。第一行输入一个整数 T 表示测试数据组数,对于每组测试数据:

第一行输入一个整数 n(1≤n≤5×105)表示序列的长度。

第二行输入 n 个整数 a1​,a2​,⋯,an​(−106≤ai​≤106)表示序列。

保证所有数据 n 之和不超过 5×105。

输出格式

每组数据输出一行 n 个由单个空格分隔的整数 v1​,v2​,⋯,vn​,其中 vi​ 表示 k=i 时的答案。

输入输出样例

输入 #1复制

2
6
1 3 -4 5 -1 -2
1
100

输出 #1复制

2 4 5 3 1 -2
100

说明/提示

对于第一组样例数据,考虑 k=3,可以将序列分割为 {{1},{3,−4},{5,−1,−2}}。答案是 1×1+2×(3−4)+3×(5−1−2)=5。

思路

贪心,取最大即可。

代码见下

#include<bits/stdc++.h>
using namespace std;
long long t,n,a[500005],b[500005],lk=0;
bool cmp(long long a1,long long b1){
    return a1>b1;
}
int main(){
	cin>>t;
    while(t--){
        cin>>n;
        for(int i=1;i<=n;i++){
            cin>>a[i];
        }
        b[n+1]=0;
        for(int i=n;i>=1;i--){
            b[i]=b[i+1]+a[i];
        }
        lk=b[1];
        sort(b+2,b+n+1,cmp);
        for(int i=1;i<=n;i++){
            if(i!=1){
                lk+=b[i];
            }
            cout<<lk<<" ";
        }
        cout<<endl;
    }
    return 0;
}

posted @ 2025-10-17 20:03  bz02_2023f2  阅读(3)  评论(0)    收藏  举报  来源