vijos1451 區間dp st表優化

2021-07-16 21:20:47 字數 1400 閱讀 7806

守護者拿出被劃分為n個格仔的乙個圓環,每個格仔上都有乙個正整數,並且定義兩個格仔的距離為兩個格仔之間的格仔數的最小值。環的圓心處固定了乙個指標,一開始指向了圓環上的某乙個格仔,你可以取下指標所指的那個格仔裡的數以及與這個格仔距離不大於k的格仔的數,取乙個數的代價即這個數的值。指標是可以轉動的,每次轉動可以將指標由乙個格仔轉向其相鄰的格仔,且代價為圓環上還剩下的數的最大值。

現在對於給定的圓環和k,求將所有數取完所有數的最小代價

很難想的dp,看到環的第一反應還是複製一遍接到後面,但是此題的「取物品」的總消耗是恆定不變的,所以可以貪心的證明,每次把指標所指處所有物品取走是最優解(或者說不能更優),所以一開始指標指向起點時,原來的環就變成了一條鏈。若指標在起點以右,那麼下一步的選擇只有再向右走一格或者走到左端點,指標在左時同理。

由此可得dp轉移方程

設f[i][j][0]表示右端點距起點間隔為i,左端點距起點間隔為j,指標在左時的情況;f[i][j][1]表示右端點距起點間隔為i,左端點距起點間隔為j,指標在右時的情況;

則:f[i][j][1] = min(f[i][j-1][1] + add, f[i][j-1][0] + add*(i+j)) //add = max

f[i][j][0] = min(f[i-1][j][0] + add, f[i-1][j][1] + add*(i+j))//add = max

處理剩餘鏈中最大值時,每次遍歷一遍的複雜讀太大,故此時用st表或線段樹進行維護,由於常數及編碼複雜度的原因,此處選擇st表。

#include

#include

#include

#include

#include

#define inf 1e15+9

using

namespace

std;

int n, k;

long

long f[2005][2005][2]; //f[i][j][0]表示指向左端點的情況 f[i][j][1]表示指向右端點的情況

int a[2005], ma[2005][20];

void make_st() //st演算法預處理

long

long rmq(int l,int r)

int main()

}long

long ans = inf;

for(int i = 0; i <= n; i++) ans = min(ans, min(f[i][n-i][0], f[i][n-i][1]));

for(int i = 1; i <= n; i++) ans += a[i];

cout

<< ans << endl;

return

0;}

7620 區間合併

7620 區間合併 總時間限制 1000ms 記憶體限制 65536kb 描述 給定 n 個閉區間 ai bi 其中i 1,2,n。任意兩個相鄰或相交的閉區間可以合併為乙個閉區間。例如,1 2 和 2 3 可以合併為 1 3 1 3 和 2 4 可以合併為 1 4 但是 1 2 和 3 4 不可以合...

4975 區間翻轉

小q和tangjz正在乙個長度為n的序列a 1,a 2,a n上玩乙個有趣的關於區間翻轉的遊戲。小q和tangjz輪流行動 小q先手。每次行動方玩家需要選擇乙個長度為4x 2或4x 3的區間 l,r 1 l r n 其中x是該玩家自行選擇 的非負整數,然後將a l,a a a r翻轉,例如1 3 2...

7620 區間合併

總時間限制 1000ms 記憶體限制 65536kb 描述 給定 n 個閉區間 ai bi 其中i 1,2,n。任意兩個相鄰或相交的閉區間可以合併為乙個閉區間。例如,1 2 和 2 3 可以合併為 1 3 1 3 和 2 4 可以合併為 1 4 但是 1 2 和 3 4 不可以合併。我們的任務是判斷...