noi 簽到題我都不會哦~
題意見洛谷。(以下用 \(k\) 表示 \(k\) 以避免與迭代變數衝突)首先有個很顯然的 dp:\(dp_\) 表示第 \(i\) 天小 w 在城市 \(j\) 的情況下獲得的最大愉悅值之和。邊界:\(dp_=\beginc_1&i=1\\-\infty&i\neq1\end\);目標:\(dp_\);狀態轉移方程:
\[dp_=\max_\+c_j+ext(i,j)\}
\]其中 \(ext(i,j)\) 表示第 \(i\) 天城市 \(j\) 通過美食節額外獲得的愉悅值。
暴力 dp 肯定是不行的。這個 \(t\) 這麼大,一臉矩陣快速冪的樣子。
考慮用矩陣的形式將狀態轉移方程寫出來。我們重定義矩陣乘法,將 \(\times\) 改為 \(+\),將 \(+\) 改為 \(\max\),學過 ddp 的都知道這樣滿足原矩陣乘法的一切性質(我沒學過 ddp 都知道)。需要注意的是,這種乘法意義下的單位元是
\[i=\begin0&-\infty&-\infty &\cdots&-\infty\\-\infty&0&-\infty&\cdots&-\infty\\-\infty&-\infty&0&\cdots&-\infty\\\vdots&\vdots&\vdots&\ddots&-\infty\\-\infty&-\infty&-\infty&-\infty&0\end
\]具體廣義乘法這套理論等到我學 ddp 再研究吧。於是:
\[\begindp_&dp_&\cdots&dp_&\cdots&dp_\end\delta_i=\begindp_&dp_&\cdots&dp_&\cdots&dp_\end
\]其中 \(\delta\) 是啥就不詳細說了,大概就是前 \(n\) 列是轉移方程裡的 \(c_j+ext(i,j)\)(如果轉移不到就是 \(-\infty\)),後 \(4n\) 列是一些 \(0\) 和 \(-\infty\) 表示移位。
注意到大多數時候 \(ext(i,j)=0\),只存在 \(\mathrm o(k)\) 個 \(i\) 使得不等於零。而所有 \(ext\) 為零的時候的 \(\delta\) 是相等的,於是考慮按有美食節的時間分段,每段快速冪,有美食節的時間暴力修改矩陣單獨轉移。
這樣複雜度為 \(\mathrm o\!\left(kn^3\log t\right)\),其中 \(n=5n\)。顯然過不去,瓶頸在於快速冪。
如何優化呢?注意到這裡是同底數冪,想到進製光速冪,即設乙個 \(x\) 進製,預處理出 \(\delta^0,\delta^,\cdots,\delta^\),其中 \(y\in[0,\lceil\log_xt\rceil]\),然後每次算冪的時候將指數 \(x\) 進製拆分乘即可。時間複雜度 \(\mathrm o\!\left(n^3x\log_xt+kn^3\log_xt\right)\)。本來就卡的很緊,似乎並沒啥卵用。
但是!這樣一來,算冪的時候每次乘法(共 \(\mathrm o(\log_xt)\) 次)可以利用矩陣乘法的結合律,將矩陣乘到向量上去,時間複雜度 \(\mathrm o(n^2)\)!然鵝直接使用快速冪的話,一次快速冪是乙個整體,無法在其過程中乘以向量;光速冪的優點是,它將乘的過程拆開了。
總時間複雜度 \(\mathrm o\!\left(n^3x\log_xt+kn^2\log_xt\right)\)。xjb 取個 \(x=2\) 即可得到 \(\mathrm o\!\left(n^3\log t+kn^2\log t\right)\) 的複雜度。由於矩陣乘法常數非常小,可以通過。
這裡「xjb 取個 \(x=2\)」,換句話說就是光速冪的優化的地方不在「光速」,而在用矩陣乘法的結合律降低單次乘法的複雜度,這大概是個矩陣乘法比較慣用的套路吧。
**:
#includeusing namespace std;
#define int long long
#define pb push_back
#define mp make_pair
#define x first
#define y second
const int inf=0x3f3f3f3f3f3f3f3f;
const int n=50,t=200,log_t=32;
int n,m,s,t;
int c[n+1];
vector> rnei[n+1];
pair> spc[t+2];
struct matrix
matrix()
friend matrix operator*(matrix x,matrix y)
friend vectoroperator*(vectorx,matrix y)
};matrix pw[log_t];
vectordp;
signed main()
for(int i=1;i<=t;i++)cin>>spc[i].x>>spc[i].y.x>>spc[i].y.y;
for(int i=0;i<5*n;i++)for(int j=0;j<5*n;j++)pw[0][i][j]=-inf;
for(int i=1;i<=n;i++)for(int j=0;js)
int e=spc[i].x-1-spc[i-1].x;
for(int j=0;jmatrix delta=pw[0];
for(int j=0;j<5*n;j++)delta[j][spc[i].y.x-1]+=spc[i].y.y;
dp=dp*delta;
} if(dp[0]<0)puts("-1");
else cout
}
洛谷P2050 美食節
修車加強版。發現每個廚師拆成p個點太浪費了,畢竟總共用到的才p個點。於是從下往上乙個乙個加,加到滿流就停。論動態加點費用流的正確姿勢.我自己加總是出現負環.我是每次加一整層,然後跑完這一層再加下一層,這樣會顯而易見的出現負環.然後我們發現如果每增廣一流量就加邊就不會出現這種毒瘤現象,因為每次加的一定...
洛谷P2050 NOI2012 美食節
題目 輸入格式 輸入檔案的第1行包含兩個正整數n和m,表示菜品的種數和廚師的數量。第2行包含n個正整數,其中第i個數為pi,表示點第i種菜品的人數。接下來有n行,每行包含m個非負整數,這n行中的第i行的第j個數為ti,j,表示第j個廚師製作第i種菜品所需的時間。輸入檔案中每行相鄰的兩個數之間均由乙個...
洛谷P2814 家譜
查詢祖先的題目,自然是要用到並查集了,不過在輸入,資料的處理上要注意細節,名字的前面 等字元顯然是分類的,可以先輸入乙個字元,然後判斷後分別處理。還有map關聯兩個字串就可以了,不用再進行編號 字元的轉換,並查集時一定要注意祖先的初始化。include include include include...