有n個數,每個數有權值。數學老師定義了區間價值為區間和乘上區間內的最小值。
現在要你找出有最大區間價值的區間是什麼,並輸出區間價值
輸入:每個輸入檔案只包含單組資料。
第一行乙個整數n。(1 <= n <= 100000)
第二行n個整數a_1,a_2,...,a_n。(0 <= a_i <= 1000000)
輸出:第一行輸出乙個整數,表示最大的區間價值。
第二行輸出兩個整數,表示區間的起點和終點。
保證答案唯一。
sample input:
610 1 9 4 5 9
sample output:
108
3 6
此題求區間和,以及區間的最小值,我們可以使用單調棧的思想
設定l陣列,記錄以a[i]為最小值的左邊邊界;
設定r陣列,記錄以a[i]為最小值的右邊邊界;
這樣,樣例中的l,r陣列為
位置:1 2 3 4 5 6
10 1 9 4 5 9
l 1 2 3 3 5 6
r 1 6 3 6 6 6
這樣,我們就可以通過計算 r[i]-l[i] 來得出區間的範圍,**怎麼實現呢?
以上**為模擬單調棧的核心**
由於區間價值是區間和*區間的最小值,所以我們要算出區間和,在這裡我們使用字首和
讀取資料時計算:
算出r[i]、l[i]後;
接下來的比較我就不說明了~
ac**:
#includeusingview codenamespace
std;
typedef
long
long
ll;const
int maxn=1e6;
ll sum[maxn];
intl[maxn],r[maxn];
inta[maxn];
intmain()
for(int i=1;i<=n;i++)
l[i]=l;
}for(int i=n;i>=1;i--)
r[i]=r;
}ll ans = -1
,l,r;
for(int i=1;i<=n;i++)
}printf(
"%lld\n
",ans);
printf(
"%lld %lld\n
",l,r);
return0;
}
這道題可以學完上面之後加以強化
注意:1、計算求和區間的最大值與最小值的差=求出所有區間的最大值-所有區間的最小值==(以a[i]為最大值的區間*區間數)-(以a[i]為最小值的區間*區間數)
2、類似1 3 1出現重複值序列,使用一次 = 判斷即可,不然會減去多乙個重複值
3、陣列不要太大,容易記憶體超限!
4、int *int 會出現溢位,因此計算時最好化為 ll ~
ac**:
#includeusingview codenamespace
std;
typedef
long
long
ll;const
int maxn=1e6+5
;int
l[maxn],r[maxn];
inta[maxn];
intmain()
for(int i=1;i<=n;i++)
l[i]=l;
}for(int i=n;i>=1;i--)
r[i]=r;
}ll sum1=0
;
for(int i=1;i<=n;i++)
//*****************************************
for(int i=1;i<=n;i++)
l[i]=l;
}for(int i=n;i>=1;i--)
r[i]=r;
}for(int i=n;i>=1;i--)
printf(
"%lld\n
",sum1);
}return0;
}
祝大家都能ac~
單調棧(陣列模擬)
1 n 1e5 1 數列中元素 1e9 輸入樣例 53 4 2 7 5 輸出樣例 1 3 1 2 2 思路 對於這種題顯然是可以暴力解決的,但要是想要優化一下就得思考一下。本題的意思是找到離某個數a z 最近的左邊的小於它的數 那麼這裡面就有個關係了 可以用乙個棧來存這些左邊的數,若x y z,且a...
NOIP模擬 奇襲 線段樹 單調棧
題意 給定數列,求有多少個區間滿足區間最大 1 區間最小 區間長度 滿足條件為 m ax 1 m in r 1 l ma x mi n r lmax 1 min r 1 l max min r l max 1 min r 1 l ma x mi n r lma x mi n l rmax min l...
NOIP模擬 字胡串(單調棧)
只剩5分鐘的時候打了乙個三重迴圈。完全沒想到固定左端點減少1個n。被diss了一波。對於乙個區間,如果他合法,那麼一定是有乙個非最大數在二進位制下與最大數有不同的地方,所以對於乙個數,利用單調棧記錄他作為最大數的區間 左右第乙個至少有一位與他不同的地方,利用容斥原理計算一下統計答案即可,複雜度 然後...