题目链接: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 }