【题解】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
-
如果需要 \(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\) 里面第一项是不用考虑的,因为两者都一样,所以就是按着后面这个东西排序。
-
如果需要 \(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\) 个必选的最大收益。
有转移:
\(j\) 是满足,\(h_i\ge h_j\wedge j<i\) 最大的 \(j\)。
但是这样是错的。因为我们并不能保证在 \(i,j\) 同时保留的情况是最优的。
比如:
这个时候肉眼可见,我们不会去选 \(j\) 而舍弃左边的大部分贡献。
实际上是可以修正的。错其实是因为 \(h_j\) 并不需要满足第一次小于 \(h_i\),枚举所有 \(h_j<h_i\) 来转移,同样线段树也可以优化。
另解:(当时以为整个做法都错了,然后就换解法了。
回到最原始的想法:按照值域来设计状态。
\(f_{i,j}\) 表示前 \(i\) 个,保留的最后高度为 \(j\)。
有转移:
这个转移对了。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\)。
转移如下:
所以就死了,因为状态设计的不完备,转移的时候会重复。
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
真的妙,完全不知道怎么想到的。