區間dp學習筆記
阿新 • • 發佈:2021-10-30
退役人回來了/fad
回來學習dp(
於是先好好學習一下區間dp吧qwq
一.什麼是區間dp
大家都知道什麼是dp吧,dp有三部曲:定義狀態,狀態轉移方程,邊界條件。
那區間dp呢?差不多,只是它有一個範圍限制,就是說它的操作只可以在這個範圍內進行。
所以我們區間dp的迴圈有三個維度:區間長度,左端點(有了左端點和區間長度右端點就出來了對不對),斷點。它們分別對應這區間dp的三個主體:階段。狀態,決策點。
乾巴巴的東西說多了沒用,我們直接看例題!
區間dp模板詳解
找了一道模板:ybt1274.合併石子
就是純模板題,要注意的就是合併操作的dp陣列需要做初始化,因為是求最小值。
直接上核心程式碼qwq?
注意:要加上的得分就是兩堆石子的數量總和,建議字首和預處理這種區間和問題。
memset(dp,0x3f,sizeof(dp)); for(int i=0;i<=n;i++)dp[i][i]=0; for(int len=2;len<=n;len++){//因為預處理過了區間長度為1的情況,所以len要從2開始qaq for(int i=1;i+len-1<=n;i++){ int j=i+len-1; for(int k=i;k<=j-1;k++){ dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+s[j]-s[i-1]); } } }
既然說到有區間限制,我們就順便說說沒用區間限制的時候。
那就是這個P1090.合併果子。
於是可以想到用貪心結合棧解決了qeq
以下是核心程式碼:
while(pq.size()>1){
x=pq.top();
pq.pop();
y=pq.top();
pq.pop();
ans+=(x+y);
pq.push(x+y);
}
三.解題報告
這個絕對會更新(
先來一個板子題的強化版。
和板子題不太一樣的點有兩個:這是一個環;要求最大和最小同時維護。
第二個簡單,第一個有難度。
於是我們來拆環為鏈!
因為對於這個環,我們隨便選一個點把它拆開,就有 \(n\)
而我們把題目中給的排列方式double一下,這個鏈就包含了所有拆分方式!
於是就很簡單了~~
核心程式碼:
for(int i=1;i<=n;i++){
cin>>a[i];
a[n+i]=a[i];
}
n*=2;
memset(minn,0x3f,sizeof(minn));
minn[0][0]=maxn[0][0]=0;
for(int i=1;i<=n;i++){
s[i]=s[i-1]+a[i];
minn[i][i]=maxn[i][i]=0;
}
for(int len=2;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
for(int k=i;k<=j-1;k++){
minn[i][j]=min(minn[i][j],minn[i][k]+minn[k+1][j]+s[j]-s[i-1]);
maxn[i][j]=max(maxn[i][j],maxn[i][k]+maxn[k+1][j]+s[j]-s[i-1]);
}
}
}
輸出操作被和諧掉了(
建議自行思考輸出什麼qeq
綠就綠在這個環了,而環的操作已經講了,直接和諧掉程式碼(bushi
非常好,這是一道和模板題基本上沒有差別的題(
程式碼被lk鴿鴿吃掉了。
5.P2858 [USACO06FEB]Treats for the Cows G/S
這個非常重要,lk鴿鴿明天再寫(“鈦晚了”
求監督lk鴿鴿不要咕咕咕