【题解】Solution Set - NOIP2024集训Day20 DP常⻅模型1「序列」

【题解】Solution Set - NOIP2024集训Day20 DP常⻅模型1「序列」

https://www.becoder.com.cn/contest/5503


「JOI 2022 Final」Let's Win the Election

挺典的类型,先贪心排序,然后 dp。

考虑两个州。\((a_1,b_1),(a_2,b_2)\)

分讨一下:(FAKE

  1. 如果需要 \(2\) 张选票。

    \(Ans_1=\min(a_1+a_2,b_1+\dfrac {a_2}2)\)

    \(Ans_2=\min(a_2+a_1,b_2+\dfrac {a_1}2)\)

    \(\min\) 里面第一项是不用考虑的,因为两者都一样,所以就是按着后面这个东西排序。

  2. 如果需要 \(1\) 张票。

    显然选 \(a\) 更小的。

\(f_{i,j,k}\)\(i\) 个州,\(j\) 张选票,\(k\) 个协助者。

\(f_{i,j,k}=\min(f_{i-1,j,k},f_{i-1,j-1,k}+\frac{a_i}k,f_{i-1,j-1,k-1}+\frac {b_i}{k-1})\)


直接不太好贪,还是得先想点性质。

先把不去的州删去,最后的决策一定是 BBBBBBAAAAAA。

如果是 BBBABBB,中间的 A 移到末尾一定不劣。

所以我们考虑枚举 B 的个数,显然如果我们确定了那些选了 B,肯定会优先选择 \(b\) 更小的,但是并不是所有 \(b\) 小的都会作为 B 被取到,可能作为 A,但一定不会不去,否则为什么不去作为一个不劣的 B 呢。

先按 \(b\) 从小到大排序。

然后还需要一次 dp。注意到选票个数其实是不必要的(因为一定是前缀)只需要定义 \(f_{i,j}\) 表示前 \(i\) 个州,\(j\) 个协助者。如果转移的时候要选 \(a\) 的话,那么就让她算到最后面去。

最后再枚举一下最后一个 \(b\) 是哪个下标,剩下的 \(a\) 从小到大取就行。(这其实还挺妙的。


「JOISC 2015 Day1」Growing Vegetables is Fun 2

最后状态下,能结果的那些草一定是山峰状的。

可以前后分别跑一遍上升的,然后枚举最高点。


考虑一个最简单的 dp,\(f_i\) 表示前 \(i\) 个第 \(i\) 个必选的最大收益。

有转移:

\[f_i=f_j+p_i-(prec_{i-1}-prec_j) \]

\(j\) 是满足,\(h_i\ge h_j\wedge j<i\) 最大的 \(j\)


但是这样是错的。因为我们并不能保证在 \(i,j\) 同时保留的情况是最优的。

比如:

image

这个时候肉眼可见,我们不会去选 \(j\) 而舍弃左边的大部分贡献。

实际上是可以修正的。错其实是因为 \(h_j\) 并不需要满足第一次小于 \(h_i\),枚举所有 \(h_j<h_i\) 来转移,同样线段树也可以优化。


另解:(当时以为整个做法都错了,然后就换解法了。

回到最原始的想法:按照值域来设计状态。

\(f_{i,j}\) 表示前 \(i\) 个,保留的最后高度为 \(j\)

有转移:

\[f_{i,j}=\begin{cases} \max_{k\le j} \{f_{i-1,k}\}+p_i & \text{ if } h_i=j\\ f_{i-1,j} & \text{ if } h_i<j\\ f_{i-1,j}-c_i & \text{ if } h_i>j\\ \end{cases} \]

这个转移对了。bf

发现最后两个其实只是对上一次的状态区间修改,而第一个只需要查询一下前缀最大值,然后单点修改就行了。

考虑用线段树维护第二维,时间复杂度 \(O(n\log n)\)


「美团 CodeM 复赛」配对游戏

假期望。拆贡献,答案就应该是每个人留下来的概率求和。

考虑求出每个人被删去的概率 \(p_i\)

对于 \(i\),枚举和她一起被删去的那个人 \(j\)

\(f_{i,0/1,0/1}\)\(i\) 个人确定最开始和结尾,全部删去的概率。

\(>\to0,<\to 1\)

那么 \(p_i=f_{|j-i|-1,0,1}\),然后就是求\(f\)

转移如下:

\[f_{i,0,1}=\frac 14\sum f_{i-2,p,q}\\ f_{i,x,y}=\frac 14\sum_{j=1}^i f_{j,x,p}\times f_{i-j,q,y}\\ \]


所以就死了,因为状态设计的不完备,转移的时候会重复。

https://www.becoder.com.cn/submission/2594703


\(>\to-1,<\to 1\)

\(f_{i,j}\)\(i\) 个,末尾剩下 \(j\) 个左/右括号的概率。(不管是左括号还是右括号,这个 dp 都是完全一样的。

转移见代码。


「PA2021 Round1 A」Od deski do deski

考虑满足条件的序列有什么性质。

我们把每对相同元素的位置看成一个区间,那么我们就是要求这些区间中的其中一些,并集是 \([1,n]\) 且没有交集。

\(O(n^2)\) check 的代码如下:

dp[0] = 1;
for (int i = 1; i <= n; i++)
    for (int j = 1; j < i; j++)
        if (a[i] == a[j])
            dp[i] |= dp[j-1];

这个性质好像有跟没有一样。😥


为了避免重复统计,我们钦定每个状态从分段数最少的来转移。

所以定义 \(f_{i,j}\) 表示前 \(i\) 个,没选过 \(j\) 的方案数。

还是没用,很难保证分段数最小是哪个。


借鉴题解的定义:\(f_{i,j,0/1}\)\(i\) 个,对于第 \(i+1\) 位有 \(j\) 种方案能使之合法(因为前面只有 \(i\) 个所以当前的 \(j\) 一定也不会超过 \(i\) 个),当前前 \(i\) 个是否合法。

这个状态定义的是真的妙。

根据刚才那个 check 的 dp 来定义(?(也算不上吧。

答案显然是 \(\sum_{j=0}^{n}f_{n,i,1}\)

https://www.luogu.com.cn/article/38i5rv5t

真的妙,完全不知道怎么想到的。

posted @ 2024-09-02 08:12  CloudWings  阅读(14)  评论(0编辑  收藏  举报