【zznu-2060】 Minsum Plus(最小正子段和)
题目描述
题意简单到令人发指!
序列A由N个整数组成,从中选出一个连续的子序列,使得这个子序列的和为正数,且和为所有和大于零的子序列中的最小值.
将这个值输出,若无解,输出no solution。
输入
第一行输入一个正整数N(2<N<50000)
第二行输入N个整数
输出
输出最小的正子段和
样例输入
3
-1 2 3
样例输出
1
思路
记录前缀和,然后排序,满足前缀和之差最小和下标递增的关系就行,注意longlong!!longlong!!
#include <bits/stdc++.h> using namespace std; const int N = 50005; typedef long long LL; struct node { LL x, y; } q[N]; bool cmp(node a, node b) { if(a.x == b.x) return a.y < b.y; return a.x < b.x; } int main() { int n, x; cin>>n; for(LL i = 1; i <= n; i++) { scanf("%d", &x); q[i].x = q[i-1].x + x; q[i].y = i; } sort(q+1, q+1+n, cmp); LL ans = 1e18; int base = 0; for(int i = 1; i <= n; i++) { if(q[i].x > q[base].x && q[i].y > q[base].y) { ans = min(ans, q[i].x - q[base].x); base++; i = base; } } if(ans == 1e18) puts("no solution"); else printf("%lld\n", ans); return 0; }
也可以利用set和lower_bound写
#include <bits/stdc++.h> using namespace std; const int N = 50005; typedef long long LL; LL a[N]; set<LL>S; int main() { int n, x; cin>>n; for(int i = 1; i <= n; i++) { scanf("%d", &x); a[i] = a[i-1] + x; } S.clear(); LL ans = 1e18; for(int i = 1; i <= n; i++) { S.insert(a[i]); if(a[i] > 0) ans = min(ans, a[i]); set<LL>::iterator it = S.lower_bound(a[i]); if(it == S.begin()) continue; it--; if(a[i] - (*it) <= 0) continue; ans = min(ans, a[i] - (*it)); } if(ans == 1e18) puts("no solution"); else printf("%lld\n", ans); return 0; }