定義\(v_ = max(a_i - a _j | l <= i, j <= r)\)。
求\(\sum_ ^ \sum_ ^ v_\),轉換\(\sum_ ^ \sum_ ^ max(a_i) - \sum_ ^ \sum_ ^ min(a_i)\)
因此這裡就轉換成了求乙個區間內的最大和最小值。
我們考慮最大值的區間覆蓋,這裡就形成了乙個單調棧了,在當前取值的左右兩側都是遞增的,因此我們得到當前值得區間覆蓋,只需要左右分別進行兩趟掃瞄,就可以得到其最左和最右的區間覆蓋,分別記為\(l[i],r[i]\)。
在這裡我們還需要考慮的一點就是當存在相同的時候, 我們要選擇最左還是最右來當乙個最大值,這樣才能保證多值相同存在的情況下我們得到的區間的合理性。這裡我選擇左側的相同值更大。
再來說一下,答案的更新,首先我們得到區間的覆蓋\(l[i],r[i]\)
我們選定i作為區間的乙個端點,可以得到\((i - l[i]) + (r[i] - i) = r[i] - l[i]\)個區間,我們假定i在區間裡,總共的區間就是\((r[i] - i) * (i - l[i])\),左右各取端點的排列嘛。
然後我們需要更新的答案就是\(a[i] * (r[i] - l[i] + (r[i] - i) * (i - l[i]))\)。
#include using namespace std;
typedef long long ll;
const int n = 1e5 + 10;
int a[n], n;
ll l[n], r[n];
ll get_max()
while(!stk.empty()) stk.pop();
for(int i = n; i >= 0; i--)
for(int i = 1; i <= n; i++)
ans += 1ll * (r[i] - l[i] + (i - l[i]) * (r[i] - i)) * a[i];
return ans;}
int main()
return 0;
}
區區區間間間(單調棧)
時間限制 c c 1秒,其他語言2秒 空間限制 c c 32768k,其他語言65536k 第一行輸入資料組數t 對於每組資料,第一行為乙個整數n,表示序列長度 接下來一行有n個數,表示序列內的元素 對於每組資料,輸出乙個整數表示答案 示例1334 2351 8439 202815 110519 1...
每日一題 區區區間間間(單調棧的應用)
原題的題意可以理解為求所有子區間的最大值減去最小值的和。即所有子區間的最大值減去最小值。我們考慮用單調棧求解。維護兩個陣列 l i r i 表示當前元素作為最大值所能到達的左邊和右邊的下標是多少 當前元素作為最值 用單調棧維護。先正著維護左區間,再倒著維護右區間。維護時的操作 當前元素大於前乙個元素...
牛客小白月賽5 區間 interval
傳送門 題目大意就是給你長度為n的區間,然後有m次操作,操作完了再查詢區間和。做法就是用字首和和差分,這是我第一次用差分,首先設乙個change陣列用來存每個位置的變化值,先清0,假如是修改 l,r 區間,該區間每個數加p的話,c l p,c r 1 p,之所以不是直接c l p,c r 1 p,是...