【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;
}

本文介绍了一种求解序列中具有最小正和的连续子序列的问题。通过记录前缀和并排序,或使用set与lower_bound方法实现。适用于解决特定类型的数据结构与算法挑战。
1万+

被折叠的 条评论
为什么被折叠?



