【瞎搞】 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; }