[9.19模拟赛]最小粒子数

谁说我不能喝 提交于 2019-11-30 11:03:31

最小粒子数\((min)\)

题目描述:

\(n\)个神奇的粒子团排成一列,第\(i\)个粒子团包含\(a[i]\)个粒子, 若 \(a[i]\)为正,则表示这个粒子团包含了\(a[i]\)个正粒子,否则包含了\(-a[i]\)个反粒子,现在科学家格里梅尔想取出连续若干个粒子团, 使得这几个团合在一起后剩下的粒子数最少(一对正反粒子会湮灭)。
另外,格里梅尔希望在满足上述条件情况下,取出尽量多的粒子团。

输入格式:

第一行输入\(N\),表示粒子团的个数。接下来\(N\)行描述\(a[i]\)

输出格式:

第一行输出一个整数,表示最少粒子的数量,第二行包含一个整数表示最多的粒子团。

样例输入:

8
-2
0
90
-30
-20
80
-70
-60
125

样例输出:

5 3

数据说明:

\(40%\)的数据\(N<=4000\)
对于许多数据,最长序列的长度唯一。
\(100%\)的数据\(N<=100000\),\(|\)每个数字的值\(|<=10^{10}\)

思路

求出前缀和,按前缀和从小到大排序,去重,每次判断相邻两个数的差,求出答案
为了防止前缀和为0的情况,可以把前缀和也和答案比较

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define ll long long
#define MAXN 200010
struct rec {
    ll sum, id;
} t[MAXN];
ll n, Max, l, r, ans;
inline ll read() {
    ll s = 0, w = 1;
    char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
    for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
    return s * w;
}
inline bool cmp(rec x, rec y) {
    return x.sum < y.sum;
}
int main() {
    //freopen("min.in", "r", stdin);
    //freopen("min.out", "w", stdout);
    n = read();
    for (register int i = 1; i <= n; i++)
        t[i].sum = t[i - 1].sum + read(), t[i].id = i;
    sort(t + 1, t + n + 1, cmp);
    Max = max(abs(t[1].sum), abs(t[n].sum));
    r = 1;
    l = 1;
    while (r <= n) {
        r++;
        if (abs(t[r].sum - t[l].sum) < Max) {
            Max = abs(t[r].sum - t[l].sum), ans = abs(t[r].id - t[l].id);
            continue;
        }
        if (abs(t[r].sum - t[l].sum) == Max) {
            ans = max(ans, abs(t[r].id - t[l].id));
            continue;
        }
        while (abs(t[r].sum - t[l].sum) > Max && l < r) l++;
        if (l == r) continue;
        if (abs(t[r].sum - t[l].sum) < Max) {
            Max = abs(t[r].sum - t[l].sum), ans = abs(t[r].id - t[l].id);
            continue;
        }
        if (abs(t[r].sum - t[l].sum) == Max) {
            ans = max(ans, abs(t[r].id - t[l].id));
            continue;
        }
    }
    for (register int i = 1; i <= n; i++) {
        if (abs(t[i].sum) < Max)
            Max = abs(t[i].sum), ans = t[i].id; 
        if (abs(t[i].sum) == Max)
            Max = abs(t[i].sum), ans = max(ans, t[i].id);   
    }
    printf("%lld\n", Max);
    printf("%lld", ans);
    return 0;
} 
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!