【 問題描述】:
小 a 是一名熱衷於優化各種演算法的 oier,有一天他給了你乙個隨機生成的 1~n 的排列, 並定 義區間[l,r]的價值為:
\[\huge c_=\max(a_i-a_j|l \le i,j \le r )
\]他想請你告訴他, 所有區間的價值的總和為多少
【 輸入】
第一行乙個數 t(<=10), 表示資料組數 對於每一組資料: 第一行乙個數 n( 1<=n,m<=100,000) 第二行 n 個數 a1...an, 表示乙個 1~n 的隨機的排列
【 輸出】
對於每組資料輸出乙個數, 表示答案
【 輸入樣例】
1
43 2 4 1
【 輸出樣例】
14
【 資料範圍】
對於 60%的資料: n<=1000
對於 100%的資料, n<=100,000
我們先看普通的暴力:
讓\(mi[l][r]\)表示從\(l\)到\(r\)區間的最小值
讓\(mx[l][r]\)表示從\(l\)到\(r\)區間的最大值
則答案為:
\[\large \sum_^\sum_^(mx[l][r]-mi[l][r])
\]但是仔細觀察式子我們可以發現:
\[\sum_^\sum_^(mx[l][r]-mi[l][r])=\sum_^\sum_^mx[l][r]-\sum_^\sum_^mi[l][r]
\]然後mx和mi的部分我們可以單獨求
所以以最大值為例子
乙個點可以管轄的範圍為左邊第乙個比他大的點到右邊第乙個比他大的點
我們設\(l[i]\)為左邊第乙個比\(a[i]\)大的位置\(r[i]\)為右邊第乙個比\(a[i]\)大的位置
則只要滿足\(l[i]並且\(i\le y 的所有區間\([x,y]\)的最小大值都為i
所以這一部分區間我們把它乘起來
然後所有區間最大值的和為
\[\large \sum_^(r[i]-i)\times(i-l[i])\times a[i]
\]最小值同理
然後求靠左/右的第乙個比他大/小的數就可以用單調棧來解決
最後把最大值的和和最小值的和相減就是答案
**:
#include#include#includeusing namespace std;
#define int long long
#define clear(x) memset(x,0,sizeof x)
const int maxn=1e5+5;
int read()
int a[maxn];
int s1[maxn],t1;
int l[maxn],r[maxn];
int n;
int ans=0;
inline void clearlr()}
signed main()
clear(s1);t1=0;
clearlr();
for(int i=1;i<=n;++i)
clear(s1);t1=0;
for(int i=n;i;--i)
for(int i=1;i<=n;++i)
cout<
} return 0;
}
NOIP提高組模擬賽3
周圍大佬都說初中打過n遍,我乙個菜雞瑟瑟發抖。把斐波那契數列寫出來找了半天性質,用了半個多小時推出來 x兔子的父親,就是x減去是在斐波那契數列中最大的小於x的數 舉個栗子 13號兔子,應減去8,得到他的祖先5 10號兔子,應減去8,得到他的祖先2 預處理出斐波那契數列,然後讓ab中較大的到他的祖先,...
NOIP提高組模擬賽4
丹青千秋釀,一醉解愁腸 無悔少年枉,只願壯志狂 矩陣字首和加暴力 o n 2m 2 60pts有手就行 觀察資料範圍,猜測應該是求一種 o n 3 的演算法,想到之前做的題,應該是 n 2 枚舉行,n 處理乙個序列的答案,然後,就沒有然後了 對於乙個序列,求子段和為k的倍數,如何 o n 求解,考慮...
NOIP提高組模擬賽6
這題看著真熟啊,好像把之前的english,入陣曲雜糅了一下。首先,像入陣曲一樣計算出字首和 s 式子可以轉化為求 s r s l 1 equiv max mod k 像english一樣 用單調棧處理出以x為最大值的區間,分區間求解 每次列舉一側區間,已知max,只要知道另一側有多少與之餘數相同的...