NOIP2023 T4 题解

T4

写出转移方程:\(f_i\) 表示前 \(i\) 天且第 \(i\) 天必须跑的最大能量值。\(g_i=\max\limits_{j=1}^i\{f_j\}\)。初值 \(f_0=g_0=0\)

对于转移方程,考虑枚举最后一段跑的段是从哪里开始的:\(f_i=\displaystyle\max_{j=i-k+1}^i(g_{j-2}+prize(j,i)-(j-i+1)\times d)\)。其中 \(prize(j,i)\)\([j,i]\) 跑获得的奖励。

注意如果 \(j=1\) 要特判。

这个转移方程是 \(O(n^2m)\) 的。我们发现,每一个跑段的起终点一定是某个挑战的起终点,所以我们可以离散化。

(注意离散化后还要数组对应到原来坐标,注意离散化后的转移可能有两种:① 上一个离散点就在前一个 ② 上一个点不相邻

然后我们发现这玩意可以用线段树优化:线段树第 \(i\) 个结点,表示当前的决策点为 \(i\) 时的值。

具体而言:

for (ll i = 1, p = 1; i <= cur; i++) { 
	while (p < i && rev[i] - rev[p] + 1 > k) //p指向当前第一个在rev[i]-k+1之后的 
		p++;
	for (auto ch: chl[i])
		st.mdf(1, 1, st.sz + 1, 1, ch.l + 1, ch.v);
	ll tmp = (rev[i - 1] == rev[i] - 1 ? max(0ll, i - 2) : i - 1); //找到上一个决策点 
	st.mdf(1, 1, st.sz + 1, i, i + 1, g[tmp] + (rev[i] - 1) * d);
	
	f[i] = st.qry(1, 1, st.sz + 1, p, i + 1) - rev[i] * d;
	g[i] = max(g[i - 1], f[i]);
}

\(rev_i\) 是离散化后的原坐标。

\(now\) 右移一个,首先要枚举所有右端点是 \(now\) 的挑战,然后对 \([lft,now]\) 进行区间加 \(prize\)

对位置 \(now\) 的决策设初值:\(g[now-1/now-2]+(rev[now]-1)\times d\)

\(f[i]=st.qry(p,i+1)-rev[i]\times d\)

为什么?我们把 \(f\) 的转移方程做变形:\(f_i=\max(g[j-1]+prize(j,i)-(i-j+1)\times d)\),其中 \(prize(j,i)\) 的累加用了线段树,而 \(-(i-j+1)\times d=(j-1)\times d-i\times d\)

所以我们在每个决策位置 \(j\) 都预先 \(+(j-1)\times d\),算 \(f_i\) 的时候只需要求 \(\max\) 再减去就行了。

(有点像斜率优化:拆式子,费用提前计算)

还有,数据卡常。不能 map 离散化,要用 sort

posted @ 2024-03-02 16:52  FLY_lai  阅读(24)  评论(0编辑  收藏  举报