1. 程式人生 > >最小正子段和 貪心

最小正子段和 貪心

復雜度 max 限制 需要 16px size typedef urn span

最小正子段和 基準時間限制:1 秒 空間限制:131072 KB N個整數組成的序列a[1],a[2],a[3],…,a[n],從中選出一個子序列(a[i],a[i+1],…a[j]),使這個子序列的和>0,並且這個和是所有和>0的子序列中最小的。 例如:4,-1,5,-2,-1,2,6,-2。-1,5,-2,-1,序列和為1,是最小的。 Input
第1行:整數序列的長度N(2 <= N <= 50000)
第2 - N+1行:N個整數
Output
輸出最小正子段和。
Input示例
8
4
-1
5
-2
-1
2
6
-2
Output示例
1


思路:先求出前綴和,然後對前綴和進行排序,排序後求出最大的相鄰前綴和之差,並且要滿足:相鄰前綴和在排序前的位置是遞增的。輸出這個答案即可

簡單地考慮一下這個算法的正確性:如果沒有進行排序,求前後兩個前綴和的差的最大值是沒有錯的,暴力計算需要O(n2
)的復雜度,
排序後,設此時的前綴和為sum[i],每個前綴和對應排序前的位置為p[i],相鄰的前綴和如果滿足更新條件,即sum[p[i]]>sum[p[i-1]]&&p[i]>p[i-1],
假設存在一個x<i-1也滿足相同條件,我們令p[i]>p[x]>p[i-1]且sum[p[i]]-sum[p[x]]<sum[p[i]]-sum[p[x]],
即存在與第i個前綴和不相鄰的前綴和sum[p[x]],第i個前綴和與第x個前綴和的差值要優於與第i-1的差值,那麽就有sum[p[x]]>sum[p[i-1]],但是x<i-1,和排序結果是矛盾的,
所以不存在x獲得排序後第i個前綴和的最優解,即最優解一定是排序後相鄰前綴和的差值。

AC代碼:
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 using namespace std;
 6 typedef long long LL;
 7 const int MAXN=5e4+10;
 8 const LL INF=1e15+10; 
 9 LL sum[MAXN];
10 int p[MAXN];
11 bool cmp(int
a, int b){ 12 return sum[a]<sum[b]; 13 } 14 int main() 15 { 16 int n,m; 17 sum[0]=0; 18 scanf("%d", &n); 19 for(int i=0;i<=n;i++) p[i]=i; 20 for(int i=1;i<=n;i++){ 21 scanf("%d", &m); 22 sum[i]=sum[i-1]+m; 23 } 24 sort(p, p+n+1, cmp); 25 LL res=INF; 26 for(int i=1;i<=n;i++){ 27 if(sum[p[i]]-sum[p[i-1]]>0&&p[i]>p[i-1]) 28 res=min(res, sum[p[i]]-sum[p[i-1]]); 29 } 30 printf("%lld\n", res); 31 }

最小正子段和 貪心