日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

51nod 1102 面积最大的矩形 新疆大学OJ 1387: B.HUAWEI's billboard 【单调栈】+【拼凑段】(o(n) 或 o(nlog(n))

發布時間:2024/4/19 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 51nod 1102 面积最大的矩形 新疆大学OJ 1387: B.HUAWEI's billboard 【单调栈】+【拼凑段】(o(n) 或 o(nlog(n)) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題面1:

題面2:

兩道題除了數據范圍不同,沒有任何差異,兩道題都可以o(n)(單調棧),o(nlog(n))(我自己的做法)解決。

解題思路1:(單調棧)

  • 對于每個點找到右邊第一個比它小的位置con1,并且找到左邊第一個比它小的位置con2。
  • 對于每個點更新答案為ans = max(ans, (con2-con1-1)*value[i])。
  • 1的做法是兩次裸的單調棧,時間復雜度為o(n)。
  • 代碼1:

    #include <bits/stdc++.h> using namespace std; typedef long long ll; //在新疆大學OJ提交需要將此處三個數組改為500010,否則會運行超時 ll a[50010]; int l[50010],r[50010]; int main(){ios::sync_with_stdio(false);int n;cin >> n;ll ans = 0;for(int i = 1;i <= n; ++i){cin >> a[i];}a[0] = a[n+1] = -1;stack<int> s;s.push(1);for(int i = 2;i <= n+1; ++i){if(a[i] < a[s.top()]){while(s.size() and a[i] < a[s.top()]){r[s.top()] = i;s.pop();}}s.push(i);}while(s.size()) s.pop();s.push(n);for(int i = n-1;i >= 0; --i){if(a[i] < a[s.top()]){while(s.size() and a[i] < a[s.top()]){l[s.top()] = i;s.pop();}}s.push(i);}for(int i = 1;i <= n; ++i){ans = max(ans, (a[i]*(r[i]-l[i]-1)));}cout << ans << endl;return 0; }

    解題思路2:(拼湊段)

  • 這是我自己瞎搞的寫法,不知道算什么方法,不過大家可以看一看思路,可能什么時候就能用到了。
  • 首先,記下輸入的數字的位置,然后對這個結構體按數字從打到小排序。
  • 遍歷這個結構體數組(這時數字是從大到下的),段(一個結構體,有l,r,used三個成員變量,l指這個段的左端位置,r指這個段的右端位置)

    a. 若這個數字的原位置的左右邊兩個數字都已形成段,則將這兩段拼成一段,具體做法是將左邊段的r延長至右端,當前數字為這一段的最小值,更新ans。
    b. 若這個數字的原位置的左邊形成段,右邊沒有形成段,則把這個數字加入到左邊的段,當前數字為這一段的最小值,更新ans。
    c. 若這個數字的原位置的右邊形成段,左邊沒有形成段,則把這個數字加入到右邊的段,當前位置為這一段的最小值,更新ans。
    d. 若這個數字的原位置的左邊和右邊都沒有形成段,則把這個數字加入到一個新的段,新的段的l和r都等于這個數字的原先位置,更新ans。

  • 可能會想到查找左邊位置所處的段和右邊所處的段需要o(n)處理起來會變成o(n^2),這時候我們加一個索引數組index,index[i]表示位置為i的數字所處的段。

  • 可能還會想到更新index需要花費o(n),處理起來會變成o(n^2),但是仔細想想我們會發現不需要更新這個段所有的index,只用更新index[l]和index[r],因為中間的在后面將不會用到。
  • 這樣算下來排序的時間復雜度是o(nlogn),處理的時間是o(n),總時間復雜度就是o(nlogn)。
  • 可能還有人問為什么正確?排序之后先插入大的,后插入小的,會發現當前插入的這個點一定是這個點的最優情況。
  • 代碼2:

    #include <bits/stdc++.h> using namespace std; typedef long long ll; //在新疆大學OJ提交需要將此處的50010全部改為500010 //輸入的數組,val為這個點的數字,idx表示原下標。 struct node{ll val;int idx; }a[50010]; //段,l表示左端,r表示右端 ,k表示段的個數。 struct segment{int l;int r; }seg[50010]; int k = 1; //index[i]表示第i個位置數字所處的段。 int index[50010];int n; bool cmp(node x,node y){return x.val > y.val; }int main(){ios::sync_with_stdio(false);int n;cin >> n;ll ans = 0;for(int i = 1;i <= n; ++i){cin >> a[i].val;a[i].idx = i;ans = max(ans , a[i].val);}sort(a+1, a+1+n, cmp);for(int i = 1;i <= n; ++i){int idxl = index[a[i].idx-1];int idxr = index[a[i].idx+1];if(idxl != 0 and idxr != 0){ //左右邊都形成一段。 seg[idxl].r = seg[idxr].r;index[seg[idxr].r] = idxl;ans = max(ans, a[i].val*(seg[idxl].r-seg[idxl].l+1));}else if(idxl != 0 and idxr == 0){ //左邊形成段,右邊未形成。 seg[idxl].r++;index[a[i].idx] = idxl;ans = max(ans, a[i].val*(seg[idxl].r-seg[idxl].l+1));}else if(idxl == 0 and idxr != 0){ //右邊形成段,左邊未形成。 seg[idxr].l--;index[a[i].idx] = idxr;ans = max(ans, a[i].val*(seg[idxr].r-seg[idxr].l+1));}else if(idxl == 0 and idxr == 0){ //左右邊均未形成段。 seg[k].l = a[i].idx;seg[k].r = a[i].idx;index[a[i].idx] = k; k++;}}cout << ans << endl;return 0; }

    總結

    以上是生活随笔為你收集整理的51nod 1102 面积最大的矩形 新疆大学OJ 1387: B.HUAWEI's billboard 【单调栈】+【拼凑段】(o(n) 或 o(nlog(n))的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。