【瞎搞】 51nod 1065 最小正子段和

通道

思路:先求一下从第一位开始的到第i位的累加,
4,-1,5,-2,-1,2,6,-2 => 4 3 8 6 5 7 13 11

对这个累加的数列排个序,然后只要判断邻近的两个数是否可以组成序列,比如4和3就不可以,因为4 > 3而4对应下标为0,3对应为1。4和5就可以,然后相同的前缀和取id最小,一开始丢个(0,0)进去。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long ll;

template <class T>
inline bool rd(T &ret) {
    char c; int sgn;
    if(c = getchar() , c == EOF) return false;
    while(c != '-' && (c < '0' || c > '9')) c = getchar();
    sgn = (c == '-') ? -1 : 1;
    ret = (c == '-') ? 0 : (c - '0');
    while(c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
    ret *= sgn;
    return true;
}

const int MAX_N = 50007;
const ll inf = (ll)1e18 + 7;

int n;
ll a[MAX_N];
pair<ll,int> v[MAX_N], v1[MAX_N];

int main() {
    rd(n);
    for (int i = 1; i <= n; ++i) rd(a[i]);
    v[0] = make_pair(0, 0);
    ll sum = 0;
    for (int i = 1; i <= n; ++i) {
        sum += a[i];
        v[i] = make_pair(sum, i);
    }
    sort(v, v + n + 1);
    int cnt = 0, id = v[0].second;
    v1[cnt++] = v[0];
    bool update = false;
    for (int i = 1; i <= n; ++i) {
        if (v[i].first == v[i - 1].first) {
            id = min(id, v[i].second);
            update = true;
        } else {
            if (update) v1[cnt - 1].second = id;
            else v1[cnt++] = v[i];
            id = v[i].second;
            update = false;
        }
    }
    pair<ll,int> pre = v1[0];
    ll ans = inf;
    for (int i = 1; i < cnt; ++i) {
        ll val = v1[i].first - pre.first;
        if (val > 0 && v1[i].second > pre.second) {
            ans = min(ans, val);
        }
        pre = v1[i];
    }
    printf("%lld\n", ans);
    return 0;
}
View Code

 

posted @ 2015-10-01 12:34  mithrilhan  阅读(186)  评论(0编辑  收藏  举报