#P2826. 第1题-TK的数组
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 67
            Accepted: 20
            Difficulty: 4
            
          
          
          
                       所属公司 : 
                              阿里
                                
            
                        
              时间 :2025年4月12日-阿里淘天(算法岗)
                              
                      
          
 
- 
                        算法标签>前缀和          
 
第1题-TK的数组
题解
题目描述
给定一个长度为 n 的数组 a1,a2,…,an,需要将数组分成两部分:前缀部分 a1,a2,…,ax 和后缀部分 ax+1,ax+2,…,an(其中 1≤x<n),使得下式达到最大值:
sumi=1x∑j=x+1nai×aj
注意:输出结果需对998244353 取模。
思路分析
题目要求求解以下表达式的最大值:

令 S 为数组所有元素之和,即
S=sumi=1nai
当我们确定了分割位置 x 后:
- 前缀部分之和为 textpre=sumi=1xai,
 - 后缀部分之和为 S−pre。
 
于是表达式可以转化为
P(x)=textpre×(S−pre)
由于数组中的每个ai均为正数,该式为一个关于pre的二次函数:

该二次函数开口向下,在理论上当textpre=S/2 时达到最大值,但由于题目要求分割位置为连续的整数位置,所以我们只需要遍历每个可能的分割位置x(1≤x<n),计算对应的P(x),并取其中的最大值,最后再对998244353取模即可。
C++
#include <iostream>
#include <vector>
using namespace std;
typedef long long ll;
const ll MOD = 998244353;
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n;
    cin >> n;
    vector<int> a(n);
    // 读取数组
    for(int i = 0; i < n; i++){
        cin >> a[i];
    }
    
    // 计算数组所有元素之和 S
    ll S = 0;
    for(int i = 0; i < n; i++){
        S += a[i];
    }
    
    ll prefix = 0;
    ll ans = 0;
    // 枚举分割位置 x,x 的取值范围为 1 到 n-1
    for(int x = 0; x < n - 1; x++){
        prefix += a[x];         // 前缀和 pre = ∑(a[0]..a[x])
        ll suffix = S - prefix;   // 后缀和 = S - pre
        ll product = prefix * suffix;  // 计算表达式值
        if(product > ans)
            ans = product;
    }
    
    // 输出答案,对 MOD 取模
    cout << ans % MOD << "\n";
    return 0;
}
Python
# 定义 MOD 值
MOD = 998244353
# 读取输入
n = int(input())
a = list(map(int, input().split()))
# 计算数组所有元素之和 S
S = sum(a)
prefix = 0
ans = 0
# 枚举分割位置,位置从 0 到 n-2(对应题目中的 1 到 n-1)
for i in range(n - 1):
    prefix += a[i]        # 累加前缀和
    suffix = S - prefix   # 后缀和
    product = prefix * suffix  # 计算表达式值
    if product > ans:
        ans = product
# 输出答案,对 MOD 取模
print(ans % MOD)
Java
import java.util.Scanner;
public class Main {
    // 定义 MOD 值
    public static final long MOD = 998244353;
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 读取数组大小 n
        int n = scanner.nextInt();
        int[] a = new int[n];
        
        // 读取数组元素
        for (int i = 0; i < n; i++) {
            a[i] = scanner.nextInt();
        }
        
        // 计算数组所有元素之和 S
        long S = 0;
        for (int i = 0; i < n; i++) {
            S += a[i];
        }
        
        long prefix = 0;
        long ans = 0;
        // 枚举分割位置,从 0 到 n-2 对应题目的分割位置 1 到 n-1
        for (int i = 0; i < n - 1; i++) {
            prefix += a[i];           // 更新前缀和
            long suffix = S - prefix;   // 计算后缀和
            long product = prefix * suffix;  // 计算表达式值
            if (product > ans) {
                ans = product;  // 更新最大值
            }
        }
        
        // 输出答案,对 MOD 取模
        System.out.println(ans % MOD);
        scanner.close();
    }
}
        题目内容
Tk有一个长度为n的数组{a1,a2,...,an},他希望将数组分割为{a1,a2,...,ax}和{ax+1,ax+2,an}两个部分(显然,x需要满足1≦x<n),使得下式的答案达到最大:
∑i=1x∑j=x+1nai×aj
这却难倒聪明的他了,现在他来寻求你的帮助,不过你并不需要告诉他具体分割位置,只需要告诉他最终结果即可。由于答案可能很大,请将答案对 998 244 353取模后输出。
输入描述
第一行输入一个正整数n(2≦n≦2×105)表示数组大小。
第二行输入n个整数a1,a2,...,an(1≦a≦104)代表数组中的元素。
输出描述
输出一个值表示上式的最大值。由于答案可能很大,请将答案对998 244 353取模后输出。
样例1
输入
5
3 2 4 1 5
输出
54
说明
分割最终区间为[1,3],[4,5],可以得到最大值54