939F Cutlet DP 線段樹優化

2021-08-25 14:41:49 字數 1625 閱讀 8182

有一塊烤肉,每面都需要烤正好n秒鐘。

現在給k個區間,你可以在這些區間內翻轉烤肉。

求最少的翻轉次數。

k<=100.

n<=1e5

首先要知道,在同乙個區間內,不可能翻轉超過兩次, 如果翻轉超過兩次,可以用兩次以內來代替。

我們定義dp[i][j]表示在第i個區間完成後,當前未烤的那面烤了j分鐘。為什麼不定義正在烤的那面烤了j分鐘呢?因為前者結果可以輕鬆表示為dp[k][n]。

假設當前i這個區間內我們翻轉了兩次烤肉,dp[i][j] = min(dp[i - 1][j - k] + 2) (k<= r[i] - l[i] 表示翻轉的區間長度)

假設當前區間翻轉了一次,dp[i][j] = min(dp[i - 1][r[i] - j - k]) (k <= r[i] - l[i])。

當前區間沒翻 dp[i][j] = dp[i - 1][j]。

這個dp時間複雜度 (n^2 * k)。

可以用線段樹求最小值,優化到(n * k * logn)

#include #include #include #include #include #include #include #include #include #include #include #ifdef local

#define debug(x) cout<

const int mod = 1e9 + 7;

const double eps = 1e-10;

const int inf = 0x3f3f3f3f;

const ll infll = 0x3f3f3f3f3f3f3f3fll;

const int maxn = 2e5 + 5;

const int mod = 1e9 + 7;

int l[123], r[123];

int d[2][maxn];

int tree[maxn * 4];

void build(int id, int l, int r, int now)

int mid = (l + r) >> 1;

build(lson, now);

build(rson, now);

tree[id] = min(tree[id<<1], tree[id<<1|1]);

}int query(int id, int l, int r, int l, int r)

int main()

build(1, 0, n, i&1);

memset(d[i&1^1], 0x3f, sizeof(d[i&1^1]));

}if(d[k&1][n/2] < inf/2) printf("full\n%d\n", d[k&1][n/2]);

else puts("hungry");

return 0;}/*

d[i][j] = min(d[i - 1][j - k] + 2)

d[i][j] = min(d[i - 1][r[i] - j - k] + 1)

d[i][j] = d[i - 1][j]

*/

線段樹 02 構建線段樹

public inte ce merger 不能再縮小的基本問題是 對treeindex指向的節點的情況進行討論 public class segmenttree 在treeindex的位置建立表示區間 l.r 的線段樹 private void buildsegmenttree int treei...

線段樹 01 線段樹基礎

物理上 public class segmenttree public int getsize public e get int index 返回完全二叉樹的陣列表示中,乙個索引所表示的元素的左孩子節點的索引 private int leftchild int index 返回完全二叉樹的陣列表示中...

線段樹和zkw線段樹

好啦,我們就開始說說線段樹吧 線段樹是個支援區間操作和查詢的東東,平時的話還是蠻實用的 下面以最基本的區間加以及查詢區間和為例 線段樹顧名思義就是棵樹嘛,葉子節點是每個基本點,它們所對應的父親就是它們的和,具體如下圖 但是對於這樣的線段樹來說,操作所需的時間是遠達不到我們的要求的 會被t 因為我們會...