1. 程式人生 > >51nod 1065 最小正字段和 解決辦法:set存前綴和,二分插入和二分查找

51nod 1065 最小正字段和 解決辦法:set存前綴和,二分插入和二分查找

idt 查找 容器 esp images 叠代 mes pre iterator

題目:

技術分享

這題要求大於0的最小字段和,常規O(n)求最大字段和的方法肯定是沒法解的。

我的解法是:用sum[i]存前i項的和,也就是前綴和。

      這題就變成了求sum[j]-sum[i]的大於0的最小值( j > i )。

      我們可以看到直接循環運算量是50000*50000,會超時。

      所以我們應該充分利用前綴和的特性。

      我們用一個set容器來裝sum。

      當算到i項時,保證前i-1項已經裝入了set中。

      我們用二分查找找到第一個比sum[i]小的值,用sum[i]減去這個值來更新答案。

      至於二分插入,set容器中插入數據用的就是二分插入。

代碼:

#include <bits\stdc++.h> 
using namespace std;
typedef long long ll;
ll sum[50010];  // sum[i]表示 1~(i-1) 項的和 
set <ll> s;     // 到第i項時,s存的是 sum[1]~sum[i-1] 
set <ll>::iterator it;  //叠代器 

int main() {
  int n;
  cin >> n;
    int mn = 2000000000;
    int key;
  for(int i = 1;i <= n; i++){
      cin 
>> key; sum[i] = sum[i-1]+key; } s.insert(0); for(int i = 1;i <= n; i++){ // lower_bound返回大於等於sum[i]的最小值 // upper_bound返回大於sum[i]的最小值 it = s.lower_bound(sum[i]); if(it != s.begin()){ it--; //it表示小於sum[i]的最大值 if
(sum - *it > 0){ mn = min((ll)mn,sum[i]-*it); } } s.insert(sum[i]); } cout << mn << endl; return 0; }

51nod 1065 最小正字段和 解決辦法:set存前綴和,二分插入和二分查找