【題目描述:】
今天是小z的生日,同學們為他帶來了一塊蛋糕。這塊蛋糕是乙個長方體,被用不同色彩分成了n個相同的小塊,每小塊都有對應的幸運值。
小z作為壽星,自然希望吃到的第一塊蛋糕的幸運值總和最大,但小z最多又只能吃m小塊(m≤n)的蛋糕。
吃東西自然就不想思考了,於是小z把這個任務扔給了學oi的你,請你幫他從這n小塊中找出連續的k塊蛋糕(k≤m),使得其上的幸運值最大。
【輸入格式:】
輸入檔案cake.in的第一行是兩個整數n,m。分別代表共有n小塊蛋糕,小z最多只能吃m小塊。
第二行用空格隔開的n個整數,第i個整數pi代表第i小塊蛋糕的幸運值。
【輸出格式:】
輸出檔案cake.out只有一行,乙個整數,為小z能夠得到的最大幸運值。
[演算法分析:]
如果是想f[i]跟前面的某個狀態有關就錯了,這不是琪露諾,可以吃完m個之後繼續吃
而是只能吃m小塊蛋糕,所以dp方程應該是這個樣子的:$$f[i] = max^ a_} + a_i$$
\[1≤i≤n
\]而求\(\sum a_\)的過程可以使用字首和優化,這樣時間複雜度便從\(o(n^3)\)優化到了\(o(n^2)\)
未優化的普通dp**:
//求max
int maxn = 1 << 31;
int e = min(i, m) - 1;
for(int j=1; j<=e; ++j)
maxn = max(maxn, sum[i-1] - sum[i-j-1]);
if(maxn > maxn + a[i]) f[i-1] = maxn;
f[i] = maxn + a[i];
而對於\(n≤500000\)的資料顯然\(n^2\)的複雜度是不達到要求的,
優化了求和,還可以優化求最大值的過程
線段樹優化的複雜度是\(o(nlog_2n)\)顯然是可以過的,但還可以用單調佇列優化到\(o(n)\).
將字首和存入單調佇列,每一次都找到當前點到隊首點的區間和,保證隊首點值最小就能使得幸運值最大,所以佇列中的元素應是從小到大排。
當隊首的位置加上\(m\)之後還是無法到大點\(i\)時,就把隊首\(pop\)掉.
單調佇列中使用int型別表示元素的位置,要訪問元素的值的話就是sum[q.front()]就好.
\([code:]\)
#include#include#includeusing namespace std;
const int maxn = 500000 + 1;
int n, m;
int a[maxn];
int sum[maxn], f[maxn];
struct node ;
dequeq;
inline int read()
while(ch>='0' && ch<='9')
x=(x<<3)+(x<<1)+ch-48, ch=getchar();
return x * f;
}int main()
for(int i=1; i<=n; ++i)
int ans = 1 << 31;
for(int i=1; i<=n; ++i) ans = max(ans, f[i]);
printf("%d\n", ans);
}
洛谷 P1714 切蛋糕 單調佇列
今天是小z的生日,同學們為他帶來了一塊蛋糕。這塊蛋糕是乙個長方體,被用不同色彩分成了n個相同的小塊,每小塊都有對應的幸運值。小z作為壽星,自然希望吃到的第一塊蛋糕的幸運值總和最大,但小z最多又只能吃m小塊 m n 的蛋糕。吃東西自然就不想思考了,於是小z把這個任務扔給了學oi的你,請你幫他從這n小塊...
洛谷P1714 切蛋糕 題解 單調佇列
題目大意 給你乙個大小為 n 的陣列,求滿足區間元素個數 le m 的連續子串行和的最大值。解題思路 假設陣列中第 i 個元素為 a i 我可以定義 sum i 表示前 i 個數之和 sum i sum i 1 a i 則,以 a i 結尾的最大連續子串行和為 sum i min sum j 我們可...
P1714 切蛋糕 單調佇列
p1714 切蛋糕 單調佇列 gyro永不抽風 最後更新 2020年09月20日 18 09 許可協議 今天是小z的生日,同學們為他帶來了一塊蛋糕。這塊蛋糕是乙個長方體,被用不同色彩分成了n個相同的小塊,每小塊都有對應的幸運值。小z作為壽星,自然希望吃到的第一塊蛋糕的幸運值總和最大,但小z最多又只能...