题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1065
题意:中文题诶~
思路:
解法1:set容器,将所有前缀和存储到set和sum数组里,再用set.upper_bound()查找sum[i]后面第一个大于sum[i]的元素,那么他们的差就是第i个元素开头的最小正子段和.然后再将sum[i]从set里面删除,不然会影响后面的查询嘛.遍历所有i就得到我们要的答案啦;
代码:
1 #include <bits/stdc++.h>
2 #define ll long long
3 #define MAXN 50010
4 using namespace std;
5
6 const int inf=0x3f3f3f3f;
7 ll sum[MAXN];
8 set<ll> st;
9
10 int main(void){
11 int n;
12 ll x, ans=inf;
13 scanf("%d", &n);
14 for(int i=1; i<=n; i++){
15 scanf("%lld", &x);
16 sum[i]=sum[i-1]+x;
17 st.insert(sum[i]);
18 }
19 st.insert(0);
20 set<ll>::iterator it;
21 for(int i=0; i<n; i++){
22 it=st.upper_bound(sum[i]);
23 if(it!=st.end()){
24 ans=min(ans, *it-sum[i]);
25 }
26 st.erase(sum[i]);
27 }
28 cout << ans << endl;
29 return 0;
30 }
解法2:将前缀和及其下标存储到pair对组(结构题也行啦)里;再以前缀和为权值sort一下,那么我们不难想到如果p[j].first>p[i].first&&p[j].second>p[i].second --条件1 的话p[j].fisrt-p[i].first 就是一段和为正数的子段的和.又因为我们已经给p排过序了,所以i,j越接近,那么得到的子段和就越小,很自然我们会想到j=i+1的情况.问题是对于j=i+1的情况上述条件1一定满足么?或者说最优解一定是来自j=i+1的情况里么?
答案是肯定的,并且我们不难证明它:我们假设排序后顺序为 i, k, j,i和j满足条件1,i和k 不满足条件1, 即:
p[j].second>p[i].second,p[k].second<p[i].second, 所以有:p[j].second>p[k].second,很显然k和j满足条件1并且k和j能比i和j产生更优的解;
所以我们只要考虑j=i+1的情况即可.
此外我们还要注意两点:1.我们排序后得到是p[i+1].first>=p[i].first 而非 p[i+1].first>p[i].first;
2.我们还要考虑p[i].first本身的值,即从第1个元素到第i个元素的和的情况
代码:
1 #include <bits/stdc++.h>
2 #define ll long long
3 #define MAXN 50010
4 using namespace std;
5
6 const int inf=0x3f3f3f3f;
7 pair<ll, int> p[MAXN];
8
9 int main(void){
10 int n;
11 ll x, ans=inf;
12 scanf("%d", &n);
13 for(int i=1; i<=n; i++){
14 scanf("%lld", &x);
15 p[i].first=p[i-1].first+x;
16 p[i].second=i;
17 }
18 sort(p, p+n+1);
19 for(int i=0; i<n; i++){
20 if(p[i].first>0){
21 ans=min(ans, p[i].first);
22 }
23 if(p[i+1].second>p[i].second&&p[i+1].first>p[i].first){
24 ans=min(ans, p[i+1].first-p[i].first);
25 }
26 }
27 cout << ans << endl;
28 return 0;
29 }