总结
时间安排
7 : 40 ∼ 8 : 40 \qquad 7:40\sim8:40 7:40∼8:40 准备对拍、随机数的板子,通读题面,开 T 1 T1 T1。 40 m i n 40min 40min 写完了第一发,对拍发现有个细节处理错了,迅速调整后拍上就过了。
8 : 40 ∼ 10 : 20 \qquad 8:40\sim10:20 8:40∼10:20 思考 T 2 T2 T2。发现 T 2 T2 T2 和之前一场模拟赛的 T 2 T2 T2 很像,都是计“树”,打算还用那道题的套路来考虑。但是发现直接统计“有一个子节点的编号大于 i i i”有些困难,去考虑正难则反,推了一会发现推不出来,打算先写暴力。但是感觉 n ≤ 6 n\leq 6 n≤6 的也不会写!阶乘级的也不好写啊……发现有一档好像是链,但是也不太会……就先跳了,开 T 3 T3 T3。
10
:
20
∼
11
:
10
\qquad 10:20\sim11:10
10:20∼11:10 考虑
T
3
T3
T3。先考虑了部分分,发现三个特殊性质可能比较好写。全是
a
a
a 的直接找前缀跟后缀拼,字符串随即均匀生成是什么?直接输出“-1”吗?不懂欸……(数据随机生成该咋用啊?)对于
w
i
=
1
w_i=1
wi=1,显然直接判当前串
S
S
S 能否构成
T
T
T 即可。然后开始想该怎么判。发现,欸,我不会!
\,
想到了一个可能有用的性质:一个字符可以被删,当且仅当包含它的前缀或不包含他的后缀中所有跟它相同的字符没有在
T
T
T 串中对应的位置出现过。中途想着想着,不知道咋就想到要设计
d
p
dp
dp 状态。开始想着,设计
d
p
i
,
0
/
1
dp_{i,0/1}
dpi,0/1 表示考虑到第
i
i
i 个字符,当前字符删/不删,能跟
T
T
T 串匹配的最大长度是多少。发现还应该附带一个
v
a
l
i
,
0
/
1
val_{i,0/1}
vali,0/1 记录当前最大长度下最小花费。但是很快这一典型错误想法就被推翻了。原因是这个状态只考虑了局部最优,无法保证全局最优,于是考虑加状态:
d
p
i
,
j
dp_{i,j}
dpi,j 表示考虑到第
i
i
i 个字符,跟
T
T
T 串匹配的长度为
j
j
j,最小花费是多少。然后发现转移很丝滑,用到上面那个貌似有用的性质了。
T
3
T3
T3
O
(
n
m
)
O(nm)
O(nm) 的暴力
d
p
dp
dp 写完后开始想优化,但是无果,看着快没时间了,就跳了。
11 : 10 ∼ 11 : 40 \qquad 11:10\sim11:40 11:10∼11:40半个小时打算迅速写 T 4 T4 T4 暴力。想着,一档 b f s bfs bfs,一档 n = 1 n=1 n=1, 16 p t s 16pts 16pts 也还行。想着 n = 1 n=1 n=1 的更好打一点就先打了。发现寄了,大了许多,发现它不能只一味向两边走,还得考虑能不能回来,就在最后 1 m i n 1min 1min 加了几句,结果还是寄, T 4 T4 T4 一点分没拿到。
考试结果
\qquad
100
+
0
+
35
+
0
=
135
p
t
s
,
R
a
n
k
:
3
100+0+35+0=135pts,\;Rank:3
100+0+35+0=135pts,Rank:3,不知道为什么 mmz 比我多
0.88
p
t
s
0.88pts
0.88pts 但是排在我下面,可能是排行榜不认识小数吧。
考试总结
\qquad 总体来说, T 2 T2 T2 耗的时间有点长,导致最终没空写 T 4 T4 T4 的暴力。考试的时候发现一道题长时间没思路,或者思路不够清晰,就可以选择直接跳,多思考其他题。
题解
T1
\qquad 果断贪心,每次删除和最大的两数中的较大的一个数。易证这一定是最优策略。用链表加线段树简单搞一搞即可。
T2
\qquad 本题与之前的某道题(多校联考 Day3 T2)很像。但是最大的不同是:上一道题要求所有儿子的编号都要小于 i i i,而本题只需一个儿子的编号大于 i i i。怎么搞?套路的,我们依旧设状态: d p i , j dp_{i,j} dpi,j 表示考虑到编号为 i i i 的点,还有 j j j 个空位的方案数。但是,这时候我们意识到一点:若还按照上道题那么转,就会少考虑一种情况:一个点两个儿子,一个编号大于 i i i,另一个编号小于 i i i 的情况。这种情况怎么处理呢?
\qquad 我们考虑增加一维状态: d p i , j , k dp_{i,j,k} dpi,j,k 表示考虑到编号为 i i i 的点,当前共有 j j j 棵树,还有 k k k 个空位,方案数。这么设计状态有什么好呢?为了解决这个问题,我们先思考下 d p dp dp 转移时的一些小细节:因为要求至少一个儿子的编号大于 i i i,那么我们如果正着转移(从 i i i 转给 i + 1 i+1 i+1),显然 i i i 中留下的空位只能让 i + 1 i+1 i+1 来填,那么就自然地满足了题目要求。有了这一点,我们想:想满足上面说的一个点两个儿子,一个编号大于 i i i,另一个编号小于 i i i 的情况,就不能只考虑让 i + 1 i+1 i+1 给前面填空,还要考虑让 i + 1 i+1 i+1 当前面点的父亲。那么当这两种情况同时考虑的时候(既填空,又当前面点的父亲),就意味着第 i + 1 i+1 i+1 个点合并了两棵树,此时就不得不加上 j j j 这一维状态了。状态设计好之后,直接分类讨论转移即可。
\qquad 核心代码:
for(int i = 1; i <= n; i ++) {
for(int j = 1; j <= i; j ++) {
for(int k = 0; k <= min(n, 2 * i); k ++) {
int p = dp[i][j][k];
for(int h = l[i + 1]; h <= r[i + 1]; h ++) {//钦定有几个儿子
if(!h) {
dp[i + 1][j + 1][k + h] = (dp[i + 1][j + 1][k + h] + p) % mod;//直接新开一个,跟原来的不沾边
if(k) dp[i + 1][j][k - 1] = (dp[i + 1][j][k - 1] + (1LL * k * p) % mod) % mod;//填空
}
if(h == 1) {//都乘2是因为要钦定这是左二子还是右儿子
dp[i + 1][j + 1][k + h] = (dp[i + 1][j + 1][k + h] + (2LL * p) % mod) % mod;//新开一棵树
dp[i + 1][j][k - 1 + h] = (dp[i + 1][j][k - 1 + h] + (2LL * k * p) % mod) % mod;//填空
}
if(h == 2) {
dp[i + 1][j + 1][k + h] = (dp[i + 1][j + 1][k + h] + p) % mod;//新开
dp[i + 1][j][k - 1 + h] = (dp[i + 1][j][k - 1 + h] + (1LL * k * p) % mod) % mod;//填空
dp[i + 1][j][k - 1 + h] = (dp[i + 1][j][k + 1] + (2LL * j * p) % mod) % mod;//分配儿子,要留一个空位
if(j > 1) dp[i + 1][j - 1][k] = ((1LL * (1LL * p * k) % mod * (j - 1) * 2) % mod + dp[i + 1][j - 1][k]) % mod;//拼接两棵树,也是要留一个空位
}
}
}
}
}
T3
\qquad 对于 n ≤ 2000 n\leq 2000 n≤2000,我们考虑设计 d p i , j dp_{i,j} dpi,j 表示考虑到 S S S 串的第 i i i 个字符,与 T T T 串匹配长度为 j j j 的最小花费。初始化为极大值, d p 0 , 0 dp_{0,0} dp0,0 是 0 0 0。那么第 i i i 个字符只有两种选择:留下或删除。若 s i = t j s_i=t_j si=tj,那么第 i i i 个字符便可考虑留下,转移为 d p i , j = min ( d p i , j , d p i − 1 , j − 1 ) dp_{i,j}=\min(dp_{i,j},dp_{i-1,j-1}) dpi,j=min(dpi,j,dpi−1,j−1);若在 T T T 串中,前缀 1 ∼ j 1\sim j 1∼j 或后缀 j + 1 ∼ m j+1\sim m j+1∼m 中不存在与 s i s_i si 相同的字符,那么第 i i i 个字符便可考虑删除,转移为 d p i , j = min ( d p i , j , d p i − 1 , j + w i ) dp_{i,j}=\min(dp_{i,j},dp_{i-1,j}+w_i) dpi,j=min(dpi,j,dpi−1,j+wi)。这么判断是因为:若前缀 1 ∼ j 1\sim j 1∼j 中有和 s i s_i si 相同的字符,后缀 j + 1 ∼ m j+1\sim m j+1∼m 中也有和 s i s_i si 相同的字符,就意味着 s i s_i si 前面后面均有字符不能被删除,那就意味着 s i s_i si 不能被删除。特殊的, d p i , 0 dp_{i,0} dpi,0 可以直接从 d p i − 1 , 0 + w i dp_{i-1,0}+w_i dpi−1,0+wi 转移来,代表 1 ∼ i 1\sim i 1∼i 全删。
\qquad 核心代码:
LL sol() {
memset(pre, 0, sizeof pre), memset(bac, 0, sizeof bac);
for(int i = 1; i <= m; i ++) {
for(int j = 1; j <= 26; j ++) pre[i][j] = pre[i - 1][j];
pre[i][(int)(t[i] - 'a' + 1)] ++;
}
for(int i = m; i >= 1; i --) {
for(int j = 1; j <= 26; j ++) bac[i][j] = bac[i + 1][j];
bac[i][(int)(t[i] - 'a' + 1)] ++;
}
memset(dp, 0x7f, sizeof dp);
dp[0][0] = 0;
for(int i = 1; i <= n; i ++) {
for(int j = 0; j <= min(i, m); j ++) dp[i & 1][j] = 0x7f7f7f7f7f7f7f7f;
for(int j = 0; j <= min(i, m); j ++) {
if(!j) dp[i & 1][j] = dp[(i - 1) & 1][j] + 1LL * w[i];
if(s[i] == t[j]) dp[i & 1][j] = min(dp[i & 1][j], dp[(i - 1) & 1][j - 1]);
if(!pre[j][(int)(s[i] - 'a' + 1)] || !bac[j + 1][(int)(s[i] - 'a' + 1)]) dp[i & 1][j] = min(dp[i & 1][j], dp[(i - 1) & 1][j] + 1LL * w[i]);
}
}
return (dp[n & 1][m] == 0x7f7f7f7f7f7f7f7f ? -1 : dp[n & 1][m]);
}
T4
\qquad
还不会