特別行動隊題解

2022-06-18 16:36:10 字數 1610 閱讀 4716

顯然遇到這種dp題我們要先打暴力,通過讀題我們可以快速推出dp式子:

狀態:設\(dp[i]\)為前i個人的最大價值

狀態轉移方程:

設\((\sum_^i a[k]) = x\)

\(dp[i] = max(dp[j] + a * x^2 + b * x + c)\)

累加我們可以直接字首和優化,設\((\sum_^i a[k]) = sum_i\)

那麼轉移方程即可化為:\(dp[i] = max(dp[j] + a * (sum_i - sum_j)^2 + b *(sum_i - sum_j) + c)\)

至此如果你不像作者一樣sb把初始化搞錯,那麼你已經有50分的高分

暴力**:

#include #include using namespace std;

const int maxn = 1000005;

long long n, a, b, c, x[maxn], sum[maxn], dp[maxn];

int main()

for (int i = 1; i <= n; i++)

}printf("%lld", dp[n]);

}

通過觀察式子,發現帶有平方以及二次項,並且不定的只有個j,再根據標籤我們斷定這道題要用斜率優化

那麼我們開始推式子(這裡已將同類項抵消):

設乙個j,k且j比k更優:

\(dp_j + a * sum_j^2 - b * sum_j - 2 * a * sum_i * sum_j > dp_k + a * sum_k^2 - b * sum_k - 2 * a * sum_i * sum_k\)

\(dp_j + a * sum_j^2 - b * sum_j - (dp_k + a * sum_k^2 - b * sum_k) > 2 * a * sum_i * (sum_j - sum_k)\)

若j在k右邊則:

若j在k左邊則:

得到兩結論:

直接可以排除掉下凸殼情況,用單調佇列維護上凸殼即可。

#include #include using namespace std;

const int maxn = 1000005;

long long n, a, b, c, x[maxn], sum[maxn], dp[maxn], q[maxn];

long long get_dp(long long i, long long j)

long long get_up(long long i, long long j)

long long get_down(long long i, long long j)

int main()

int head = 0, end = 0;

for (int i = 1; i <= n; i++)

printf("%lld", dp[n]);

}

最後提一下,這道題有維護下凸殼的做法,就是將a直接移到左邊即:

但是這樣因為\(a < 0\), 所以不等號方向改變,結論也隨之逆轉(我就因為打這個調了半天),進而要維護下凸。比較難調,以並不推薦這種做法。

特別行動隊題解

刷水題什麼的最愉快了。題意十分明了,就是選出一種分配方案將士兵分為若干組,使修正後的戰鬥力最大。我們先可以寫出暴力dp轉移 設 f n 為將前 i 個士兵分組,且第 i 個士兵為最後一組最後乙個的最大戰鬥力。f i max x j 則化為 f i max tmp,q n inline int rea...

特別行動隊 斜率優化

apio2010特別行動隊 令s為字首和,那麼n方dp f i max 展開,移項得到 f j a s j s j 2 a s i b s j f i a s i s i b s i c。即以f j a s j s j 為y,s j 為x的一次函式,用斜率優化。因為斜率單調遞減,所以維護乙個單調遞減...

APIO2010 特別行動隊

你有一支由 n 名預備役士兵組成的部隊,士兵從 1 到 n 編號,要將他們拆分 成若干特別行動隊調入戰場。出於默契的考慮,同一支特別行動隊中隊員的編號 應該連續,即為形如 i,i 1,i k i,i 1,i k 的序列。編號為 i 的士兵的初始戰鬥力為 xi 一支特別行動隊的初始戰鬥力 x 為隊內 ...