You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4.0 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

AcWing 455. 小朋友的数字

一、题目描述

n 个小朋友排成一列。

每个小朋友手上都有一个数字,这个数字可正可负。

a[i]

规定每个小朋友的 特征值 等于排在他前面(包括他本人)的小朋友中连续若干个(最少有一个)小朋友手上的数字之和的最大值。

注:b[i],特征值=最大子段和

作为这些小朋友的老师,你需要给每个小朋友一个 分数 ,分数是这样规定的:

c[i]

第一个小朋友的分数是他的特征值

c[1]=b[1]

其它小朋友的分数为排在他前面的所有小朋友中(不包括他本人),小朋友分数加上其特征值的最大值。 

请计算所有小朋友分数的最大值,输出时保持最大值的符号,将其绝对值对 p 取模后输出。

输入格式 第一行包含两个正整数 n、p,之间用一个空格隔开。

第二行包含 n 个数,每两个整数之间用一个空格隔开,表示每个小朋友手上的数字。

输出格式 输出只有一行,包含一个整数,表示最大分数对 p取模的结果。

数据范围 1≤n≤10^6,1≤p≤10^9,其他数字的绝对值均不超过10^9

输入样例1

5 997
1 2 3 4 5

输出样例 1

21

输入样例 2

5 7
-1 -1 -1 -1 -1

输出样例 2

-1

二、前置知识

AcWing 126. 最大的和

https://www.acwing.com/solution/content/192382/

三、解题思路

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
const int N = 1000010;
int n, p; // n个小朋友模p
LL f[N];  // DP数组前序最大子段和

int main() {
    cin >> n >> p; // n个小朋友模p
    LL s = 0, mx = -1e18;
    for (int i = 1; i <= n; i++) {
        int x;
        cin >> x;
        s = max(s, 0ll) + x; // 最大子段和的套路,如果能继承父亲的财产就继承,如果父亲只有债务,就不管
        mx = max(mx, s);     // 到i为止可以获得的最大子段和
        f[i] = mx;           // 保存到dp数组f[N]中
    }

    /*
      ① 每个小朋友的特征值等于排在他前面(包括他本人)的小朋友中连续若干个
      (最少有一个)小朋友手上的数字之和的最大值。
      ② 第一个小朋友的分数是他的特征值,
      其它小朋友的分数为排在他前面的所有小朋友中(不包括他本人),小朋友分数加上其特征值的最大值。 
    */
    LL res = f[1]; // 第一个小朋友的得分目前是大王

    LL score = f[1] * 2; // 第二个小朋友的得分 = 第一个小朋友的得分+第一个小朋友的特征值

    for (int i = 2; i <= n; i++) {   // 从第二个小朋友开始,到最后一个小朋友枚举
        res = max(res, score);       // res:记录最大分数
        if (f[i] > 0) score += f[i]; // 如果最大子段和大于0可以接在后面
    }
    printf("%lld\n", res % p); // 对p取模输出
    return 0;
}

上面的代码只能通过10/12,不能AC,因为会爆long long,办法就是用\_\_int128

#include <bits/stdc++.h>

using namespace std;
typedef __int128 LL;
const int N = 1000010;
int n, p;
LL f[N];
LL max(LL a, LL b) {
    if (a >= b) return a;
    return b;
}
int main() {
    cin >> n >> p;
    LL s = 0, mx = -1e36;
    for (int i = 1; i <= n; i++) {
        int x;
        cin >> x;
        s = max(s, 0) + x;
        mx = max(mx, s);
        f[i] = mx;
    }
    LL res = f[1], score = f[1] * 2;
    for (int i = 2; i <= n; i++) {
        res = max(res, score);
        if (f[i] > 0) score += f[i];
    }
    printf("%lld\n", res % p);
    return 0;
}