51nod1065(set.upper_bound()/sort)

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

 

posted @ 2017-01-21 16:16  geloutingyu  阅读(233)  评论(0编辑  收藏  举报