首页 > 其他分享 >「CSP-S」 做题记录

「CSP-S」 做题记录

时间:2024-09-29 18:11:47浏览次数:1  
标签:子串 CSP 子树 .. 记录 sum operatorname 节点

「CSP-S」做题记录

  1. [CSP-S2019 江西] 多叉堆

    自己做出来了,开心捏。

    先考虑对于一棵特定的树,如何计算答案(对应特殊性质 1)。

    首先,根节点一定只能填 \(0\)。其次,可以发现各个子树不会互相影响,所以可以分别考虑如何填各个子树。

    设填满以节点 \(u\) 为根的子树的方案数为 \(f(u)\),\(u\) 的子节点数量为 \(m\),子节点分别为 \(v_1, v_2, \dots, v_m\)。沿用”组合-顺序“的思考路径:设把 \((|T(u)|-1)\) 个节点(这里减去了根节点)分给 \(u\) 的各个子树的方案数为 \(cnt(u)\),而在此基础上给各个子树安排顺序的方案数为 \(f(v_1) \times f(v_2) \times \cdots \times f(v_{m})\),从而可以得到 \(f(u)\) 的表达式:

    \[f(u) = cnt(u) \times \prod_{i=1}^{m} f(v_i) \]

    递归的边界条件是当 \(u\) 为叶子节点时,\(f(u) = 1\)。

    下面只需考虑如何计算 \(cnt(u)\)。实际上这就是多重组合数问题:把 \((u-1)\) 个数分为 \(m\) 组,第 \(i\) 组有 \(|T(v_i)|\) 个,方案数为

    \[cnt(u) = \dbinom{|T(u)| - 1}{|T(v_1)|, |T(v_2)|, \dots, |T(v_m)|} = \dfrac{(|T(u)|-1)!}{\prod_{i=1}^{m} |T(v_i)|!} \]

    dfs 一遍即可得到答案。这样可以拿到 35 分

    下面考虑带修的情况。注意到每次修改只是把一个子树的根节点 \(v\) 连向另一个子树的根节点 \(u\),这只对 \(f(u)\) 有影响。我们只需快速更新 \(f(u)\) 的值。

    考虑加入新的子树对 \(f(u)\) 的影响。分两部分讨论:

    • \(cnt(u)\):把式子展开,前缀积维护。
    • 顺序(子节点的 \(f\) 的积):再乘上 \(f(v)\) 即可。

    于是这道题就做完了。(提交记录


    别解

    (下面把点的编号转为 1-indexed。)

    把树的每一条边定向为从父节点指向子节点,得到一棵有向树。此时,合法的填数方案和树的拓扑序一一对应:按照节点在拓扑序中出现的位置填数,就可以保证合法。

    下面计算树的拓扑序的数量。

    澄清:一般 DAG 的拓扑序计数没有多项式解法,但某些特殊图(如树)是有的。

    设 \(U\) 表示所有长度为 \(n\) 的排列构成的集合,显然 \(|U| = n!\)。

    设 \(P_u\) 表示满足下列条件的排列的集合:\(u\) 出现在其子树内除它本身以外的所有点之前。设 \(size(u)\) 表示 \(u\) 的子树大小。对于任意一个排列,考察这个排列中 \(T(u)\) 中的所有点。对这些点重新排列,而其他点的位置不改变,总共可以得到 \(size(u)!\) 个排列,而其中恰有一个满足条件。也就是说,每 \(size(u)!\) 个排列中,就有 \(1\) 个符合要求的排列。因此 \(P_u = \dfrac{1}{size(u)!}|U| = \dfrac{n!}{size(u)!}\)。

    设能作为拓扑序的排列的集合为 \(A\),则 \(A = \bigcup_{i=1}^{n} P_{i}\)。

    下面不会了。

    总之,拓扑序的数量是

    \[\prod_{i=1}^{n} \dfrac{1}{size(i)!} \times n! \]

  2. [CSP-S2019 江西] 和积和

    考虑枚举 \(l \in [1, n]\),对于每个 \(l\),计算它对答案的贡献 \(f(l) = \sum_{r=l}^{n} S(l, r)\)。

    假设已知 \(f(l)\),考虑如何更新到 \(f(l+1)\)。

    拆式子:

    \[\begin{aligned} f(l) &= \sum_{r=l}^{n} \operatorname{sum}(a_{l..r})\operatorname{sum}(b_{l..r}) \\ &= \sum_{r=l}^{n} (a_{l} + \operatorname{sum}(a_{l+1..r}))(b_{l}+\operatorname{sum}(b_{l+1..r})) \\ &= \sum_{r=l}^{n} (a_l b_l + a_l \operatorname{sum}(b_{l+1..r}) + b_l \operatorname{sum}(a_{l+1..r}) + \operatorname{sum}(a_{l+1..r})\operatorname{sum}(b_{l+1..r})) \\ &= (n-l+1) \cdot (a_l b_l + \operatorname{sum}(a_{l+1..r}) \operatorname{sum}(b_{l+1..r})) + a_{l}\sum_{r=l+1}^{n} \operatorname{sum}(b_{l+1..r}) + b_l \sum_{r=l+1}^{n} \operatorname{sum}(a_{l+1..r}) \end{aligned} \]

    算了还不会。

  3. [CSP-S 2023] 消消乐

    • \(O(n^3)\) 35pts

      区间 dp。

      设 \(f(l, r)\) 表示子段 \([l, r]\) 能否被消除。

      • 初始化:\(\forall 1 \le i < n\),\(f(i, i+1) = [str_i = str_{i+1}]\)

      • 转移:

        可以发现,合法子串可以归为两种形式:

        1. \(AB\),其中 \(A\) 和 \(B\) 代表合法子串。也就是说一个合法子串可以由两个合法子串拼接而来。
        2. \(cAc\),其中 \(c\) 代表单个字符。即在一个合法子串的两端加上相同字符,得到的仍然是合法子串。

        于是可以按这两种类别转移:

        1. 枚举 \(l < k < r\),把 \([l, r]\) 拆成 \([l, k] \cup [k+1, r]\),如果两段都可以被消除,则 \([l, r]\) 是合法子串。
        2. 如果 \(s_{l} = s_{r}\) 并且 \([l+1, r-1]\) 可被消除,则 \([l, r]\) 是合法子串。
      • 答案统计:\(ans = \sum_{l, r} [f(l, r)]\)

    • \(O(n^2)\) 50pts

      在此基础上优化。

      转移第一种方案时,我们每次要枚举断点。考虑优化这个过程。

      设 \(g(l)\) 表示最大的 \(r\),使得 \([l, r]\) 可以被消除。这样,转移时就不用枚举断点,而只用 \(f(g(l)+1, r)\) 来更新。容易证明这是正确的。

    • \(O(n|\Sigma|)\) 100pts

      (从这里开始是看题解想的。)

      现在 dp 的状态数是 \(O(n^2)\),这种状态设计决定了时间复杂度下界是 \(O(n^2)\)。要获得更优的做法,必须改变状态设计。

      设 \(f(i)\) 表示以 \(i\) 结尾的合法子串数量,则 \(ans = \sum_{i=1}^{n} f(i)\)。

      设 \(g(i)\) 表示最大的能使 \([g(i), i]\) 为合法子串的数。于是 \(f(i) = f(g(i) - 1) + 1\)。

      于是我们只要找出办法求出 \(g(i)\) 即可。

      可以发现如下性质:\([g(i), i]\) 一定是 \(cAc\) 形式的。否则若 \([g(i), i]\) 是 \(AB\) 形式的,那么 \(B\) 以 \(i\) 结尾并且可被消除,与 \(g(i)\) 的最大性矛盾。因此,\(s_i = s_{g(i)}\)。

      初始化 \(g(i) = i - 1\)。应用如下算法:重复 \(g(i) \gets g(g(i)) - 1\),直到 \(s_{g(i)} = s_i\) 或 \(g(i) = 0\)。(后者表明没有以 \(i\) 结尾的合法子串。)

      为什么这是对的呢?

      当 \(i = 1\) 时,显然没有以 \(i\) 结尾的合法子串,此时 \(g(i) = 0\)。


      别解

  4. P9755 [CSP-S 2023] 种树

    • 特殊性质 A (25pts)

      其实自己想了一个贪心,但是以为是假的,没有多加思考就弃了,看了题解才知道这是对的。对于贪心,还是仔细得论证其正确性啊。

      \(c_i = 0\),说明第 \(i\) 棵树每天生长的高度是定值 \(b_i\),它生长到 \(a_i\) 需要的天数 \(t_i = \left\lceil \dfrac{a_i}{b_i} \right\rceil\)。

      按 \(t_i\) 从大到小排序,枚举 \(i\),如果它还没有被种下,则种下它到根节点简单路径上的所有未被种下的树。不难发现,这个贪心是正确的。

    • 特殊性质 B-链 (10pts)

      在链上,种树的顺序被固定了,我们只需求出每棵树生长到对应高度的时间。

      对于第 \(i\) 棵树,假设它在第 \(l\) 天被种下(实际上在这里有 \(l = i\),因为我们是按顺序种的,且显然在种满之前我们每一天都会种树),在第 \(r\) 天完成任务,我们希望能求出 \(r\),也就是解以下不等式:

      \[\sum_{d=l}^{r} (b_{i} + d \times c_{i}) \ge a_{i} \\ (r-l+1)b_{i} + \dfrac{1}{2}(l+r)(l+r-1)c_{i} \ge a_{i} \]

      整理到这一步,会发现很难把 \(r\) 孤立出来。不妨换一个思路:不必解出 \(r\),而使用二分求出 \(r\):

      i64 calc(int x, int L) // 在第L天种下第x棵树,求它在第几天满足条件
      {
      	auto check = [&](int R) -> bool
      	{
      		i128 h = 0;
      		if(p[x].c >= 0)
      		{
      			h = (R - L + 1) * p[x].b + p[x].c * (L + R) * (R - L + 1) / 2;
      		}
      		else
      		{
      			i128 m = ceil(1 - p[x].b, p[x].c) - 1;
      			if(m >= R) h = (R - L + 1) * p[x].b + p[x].c * (L+R) * (R-L+1) / 2;
      			else if(L <= m && m < R)
      			{
      				h += (m - L + 1) * p[x].b + p[x].c * (L + m) * (m - L - 1) / 2;
      				h += (R - m);
      			}
      			else h = (R - L + 1);
      		}
      		return h >= p[x].a;
      	};
      	
      	int l = L, r = 1e9, ret;
      	while(l <= r)
      	{
      		int mid = (l + r) >> 1;
      		if(check(mid)) ret = mid, r = mid - 1;
      		else l = mid + 1;
      	}
      	return ret;
      }
      
    • \(O(n \log V \log n)\) 满分做法

标签:子串,CSP,子树,..,记录,sum,operatorname,节点
From: https://www.cnblogs.com/dengstar/p/18440550

相关文章

  • 「比赛记录」AtCoder abc373 (9.28)
    CTH想看F题解,于是先发出来F.KnapsackwithDiminishingValues属于是翻译官方题解了首先我们设\(dp_{w,j}\)表示从权重为\(w\)或更小的物品中选总重为\(j\)的物品可以得到的最大幸福度。考虑\(dp\)的转移。我们把所有物品按照权重\(w\)分为多组,(每一组中所有物品......
  • spring 常见注解记录+ 使用自定义注解与aop 记录接口请求参数
    注解定义:importjava.lang.annotation.Documented;importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;importorg.springframework.core.annotation.Alias......
  • 论文速读记录 - 202409
    这次是KDD2024专场。目录:DeepBag-of-WordsModel:AnEfficientandInterpretableRelevanceArchitectureforChineseE-Commerce【词袋模型和语言模型结合,构建可解释的相关性计算方法】UnderstandingtheRankingLossforRecommendationwithSparseUserFeedba......
  • 小主机虚拟化平台搭建记录
    小主机搭建虚拟化的一些记录:1,如果主机是Intel平台,目前建议还是使用VMwareEsxi6.7,如果你的主机网卡驱动没有包含在ESXI官方安装包内,去恩山找封装了网卡驱动的版本https://www.right.com.cn/FORUM/thread-7881507-1-1.html 2,如果你的主机是AMD平台,并且是ZEN系列,那么优先选......
  • csp-s模拟6
    A.一般图最小匹配\(m\)小于\(\frac{n}{2}\)所以对原数组排序后做差分,差分后的数不能选相邻的,设\(f_{i,j,0/1}\)表示前\(i\)个,选了\(j\)个,第\(i\)个选没选直接\(dp\)求最小值就行点击查看代码#include<bits/stdc++.h>constintmaxn=5001;usingnamespacestd......
  • 记一次触发器用最新一条记录更新另外一条记录字段值的操作
    查询数据库里面最新一条记录的正确思路数据库里面的记录肯定有时间字段,找到时间的最大值,在where里面查询最新的的时间触发器查询的时候应该加上时间限制,不然随着时间的推移查询越来越慢触发器应该是beforeinsert类型不然会存在递归引用使用oracle函数或者mysql函数来执行时......
  • Git仓库代码在不同操作系统里结尾^M问题的记录
    每次按键盘上的Return时,会插入一个称为行结束符的不可见字符^M。不同的操作系统处理行结束符的方式不同。在使用Git或者GitHub协作处理项目时,Git可能产生意外结果。例如,您在Windows计算机上操作,而您的协作者是在macOS或者Linux中做的更改。您可以将Git配置为自动处理行结束符,以......
  • 浅浅记录学习情况叭
    BasicConcepts对于一个给定的网络G=(V,E),其中V为网络的节点集,E为网络的边集.Trace(迹):将G划分为q个社区,我们用一个qxq的对称矩阵e来表示该划分,e中的每个元素表示连接社区i与社区j的边在G的全部边中所占的比例显然有∑i,jeij=1。矩阵e的迹Tr(e)表示连接社区内部节点的边......
  • csp-s模拟5
    A.光来自\(K8\)的神奇做法,根据贪心思想,一个点减四个亮度可以收益最大化,所以枚举四个灯亮度都不足4时的最终态,然后看剩下需要亮度需要减的次数,每次选最大的那个操作就行,复杂度\(O(16n)\)点击查看代码#include<bits/stdc++.h>constintmaxn=1e5+10;usingnamespacestd;......
  • [赛记] csp-s模拟5
    光100pts赛时打的错解A了,就很神奇;其实可以发现答案有可二分性,考虑二分答案,每次check时枚举左上角和右下角的耗电量,然后对左下角的耗电量再进行二分,最后判定以下即可;赛时就这么打的,然后赛后拍出来了;其实这个思路是对的,只是$\lfloor\fracn4\rfloor$这个条件有误差,所以暴......