luogu 记录

luogu 记录

P8215 分组作业

题面:

老师布置了分组作业。在此之前,老师将班上 \(2n\) 个学生分成了 \(n\) 组,每组两个人。其中 \(1\) 号和 \(2\) 号为一组,\(3\) 号和 \(4\) 号为一组,……,\(2n-1\) 号和 \(2n\) 号为一组。

老师让每个队伍自行安排分工。这样是否合作就成了一个大问题。大家决定用表决的方式来确定。首先每个人决定是否愿意和队友合作。不同的人因为自己的原因和分配的队友的原因,对合作的意愿不一样,对于第 \(i\) 个学生,选择“愿意”会产生 \(c_i\) 的不满,选择“不愿意”会产生 \(d_i\) 的不满。

如果两名队友都选择“愿意”,那么根据实际情况他们可以合作或者不合作。但是如果有一名队友选择“不愿意”,那么他们只能不合作。

学生中还有 \(m\) 个单向的喜欢关系,一个关系形如“\(A\) 喜欢 \(B\)”。在这样一个关系中,如果 \(A\) 没有和队友合作,且 \(B\) 选择了“愿意”,\(A\) 会有略微沮丧,产生 \(a_i\) 的不满;如果 \(A\) 表决了“不愿意”,但 \(B\) 成功与队友合作,那么 \(A\) 会羡慕嫉妒恨并产生 \(b_i\) 的不满。(由于当 \(A\)\(B\) 在同一组时这种设定会变得很奇怪,所以题目保证不会有这种情况)其中 \(i\) 表示第 \(i\) 个关系。

如果一个学生 \(i\) 选择了“愿意”但是他的队友选择了“不愿意”,那么他会因为队友产生 \(e_i\) 的不满。

问所有情况下最小的不满之和是多少。

\(1\le n \le 5000\)\(0\le m \le 10000\)\(1\le a_i,b_i,c_i,d_i,e_i\le 10^9\)

题解:

智慧的网络流建图题。

套路的,每个学生都是一个点 \(i\),他有两种选择,都需要付出相应的代价,转化为最小割问题,割到 \(S\) 点集或是 \(T\) 点集分别对应两种选择。即建立边 \((S,i,d_i)\)\((i,T,c_i)\) 我们分别称之为 \(d\) 类边和 \(c\) 类边。

之后再建立对每一组同学 \((i,i+1)\) 建边 \((i,i+1,e_i)\)\((i+1,i,e_{i+1})\)(称之为 \(e\) 类边),表示如果两个人选择状态不一样就会有经过对应 \(e\) 边的 \(S\) 可达 \(T\) 的路径,那就还需要割掉某个 \(e\) 边。

最高妙的地方就是如何处理“喜欢”的限制。

对每组建立点 \(x_i\) 对应组 \((2i-1,2i)\)。若割断后 \(S\) 能到达 \(x_i\) 表示 \(i\) 组选择合作,否则表示不合作。然后建边 \((x_i,2i-1,inf),(x_i,2i,inf)\) (称之为 \(i\) 类边)。

对于每个关系 \(A\) “喜欢” \(B\),建边 \((B,x_{\lceil A/2\rceil},a_i),(x_{\lceil B/2\rceil},A,b_i)\) 称之为 \(a\) 类边和 \(b\) 类边。

正确性可以分类讨论证明。

首先对于 \(a\)\((i,x_j,a_k)\),如果 \(x_j\) 里的组员 \(y\) 选择了不愿意,而 \(i\) 选择了愿意,那么就会有路径 \(S\to i\to x_j\to y\to T\),所以 \(a_k\) 是一定会被割掉的。(不可能不割掉 \(a_k\),如果 \(a_k\) 不割那么由于 \(i\) 边的存在 \(c_{2j-1}\)\(c_{2j}\) 都会割掉,那么 \(y\) 选择不愿意时的 \(d_y\) 就不用割了。)

若一个组 \(x_i\) 只有 \(b\) 边,那么不管组员怎么选都肯定不合作,答案不会变劣,对应到图上即 \(x_i\) 没有入边,所以 \(S\) 也必然不能到达 \(x_i\)

若一个组 \(x_i\) 只有 \(a\) 边,上述论证了如果有人不愿意那 \(a_k\) 肯定会割掉,如果都愿意那选择合作答案肯定不会变劣,这对应了如果两条 \(c\) 边全部割掉那一定没有 \(S\)\(x_i\) 可达 \(T\) 的路径,所以 \(a\) 边也不用割了。

若一个组 \(x_i\) 同时有 \(a,b\) 两种边,那么他割掉的边中肯定不会同时有 \(a,b\) 两种边,这肯定不如把所有 \(a\) 边全割掉或把所有 \(b\) 边全割掉更优。此时若他割掉所有 \(a\) 边表示 \(x_i\) 组不合作,反之表示合作。这两种情况正好分别对应了题目中“喜欢”的两种惩罚状态。

P4548 歌唱王国

题面:

在歌唱王国,所有人的名字都是一个非空的仅包含整数 \(1\sim n\) 的字符串。

王国里生活着一大群咕噜兵,他们靠不停地歌唱首领——牛人酋长们的名字来获取力量。咕噜兵每一次歌唱过程是这样的:首先,他从整数生成器那儿获得一个数字,然后花一个时间单位将此数字唱出来,如果他发现某个牛人酋长的名字已经被歌唱出来(即此名字是歌唱序列的一个连续子串),那么这次歌唱过程就立即结束。

相关名词定义:

  • 歌唱序列:如果某人歌唱了 \(x\) 个数字,第 \(i\) 次歌唱的数字为 \(a_i\),那么歌唱序列 \(=(a_1,a_2,\cdots,a_x)\)
  • 整数生成器:歌唱王国的神物,它有一个按钮,如果你按一下按钮,将从 \(1\sim n\) 数字中等概率的随机返回一个整数。
  • 歌唱时间:在一次歌唱过程中花费的时间。

歌唱时间是随机的,无法预料;不过歌唱时间的期望值是固定的,此期望值即平均来说歌唱时间有多长,亦可称作平均歌唱时间。

王国里的人非常喜欢歌唱,他们希望歌唱的时间越长越好,所以他们决定罢免一些牛人酋长,使得平均歌唱时间变长。但是他们不能罢免掉所有的牛人酋长,否则他们每次歌唱都无法停止,无法获取力量;于是他们决定只保留一个牛人酋长而罢免其余的牛人酋长。

你的任务是:对于给定的 \(n\)、牛人酋长的个数 \(t\) 以及每一个牛人酋长的名字,告诉王国里的人们,对于 \(1\leq i\leq t\),如果保留第 \(i\) 个牛人酋长,罢免掉其余的,那么平均歌唱时间将是多少。

提示:此数为一个非负整数!

输出要求:由于这个数字太大,所以你只需输出这个数的末 \(4\) 位数字。如果不足 \(4\) 位,则前面补 \(0\)\(1\leq n\leq 10^5\)\(t\leq 50\)\(1\leq m_i\leq 10^5\)

题解:

题目即要求对于每个模式串求在文本串中第一次出现的期望长度。

考虑 \(kmp\) 的匹配过程,设当前模式串 \(s\) 长度为 \(k\)\(f(i)\) 表示文本串当前匹配到了模式串的第 \(i\) 个字符之后直到结束还需要的期望步数。初始 \(f(k)=0\)

有转移方程 \(f(i)=1+\frac 1 n\sum_{c=1}^nf(tr(i,c))\)\(tr(i,c)\) 表示前 \(i\) 个字符已经匹配上之后在加入一个字符 \(c\) 会匹配到模式串的哪个位置。即若 \(c=s_{i+1}\),那么 \(tr(i,c)=i+1\),否则 \(tr(i,c)=tr(nxt_i,c)\)

注意到 \(tr(i,c)\)\(tr(nxt_i,c)\) 的结果只有当 \(c=s_{i+1}\) 时不同,所以设 \(j=nxt_i\)\(f(j)-\frac 1 nf(tr(j,s_{i+1}))=f(i)-\frac 1 nf(tr(i,s_{i+1}))\)

因为 \(tr(i,s_{i+1})=i+1,tr(nxt_i,s_{i+1})=nxt_{i+1}\) 化简得 \(f(nxt_i)-f(i)=\frac 1 n(f(nxt_{i+1})-f(i+1))\)

\(g(i)=f(nxt_i)-f(i)\),有转移 \(g(i)=\frac{g(i+1)} n\),边界是 \(g(1)=f(0)-f(1)\)。根据 \(f\) 的转移方程有 \(f(0)=1+\frac{n-1} n f(0)+\frac 1 n f(1)\),即 \(f(0)-f(1)=n\),所以 \(g(1)=n\)\(g(i)=n^i\)

因为 \(f(k)=0\),所以 \(g(k)=f(nxt_k)=n^k\),同理 \(f(nxt_{nxt_k})=n^k+n^{nxt_k}\)。所以答案是从 \(k\) 开始跳 \(nxt\)\(n\) 的沿途位置次幂加和。

P4218 [CTSC2010] 珠宝商

题面:

给定一个长为 \(m\) 的串 \(T\) 和一个 \(n\) 个点的树,每个点有一个小写字母。记 \(str_{u,v}\) 表示 \(u\)\(v\) 的路径上的点连接成的字符串。

\(P(S)\) 表示字符串 \(S\)\(T\) 中的出现次数。求 \(\sum_{u,v}P(str_{u,v})\)\(n,m\leq 50000\)

题解:

处理树上所有路径问题考虑点分治。设当前分治重心为 \(x\),每个点在当前连通块中以 \(x\) 为根时子树大小是 \(siz_x\)

要求出 \(\sum_{x\in {\rm path}(u,v)}P(str_{u,v})\)

\(lpos(S),rpos(S)\) 表示字符串 \(S\)\(T\) 中所有出现位置的左/右端点集合。

式子可变型为 \(\sum_p\sum_u\sum_v[p\in rpos(str_{u,x})][p\in lpos(str_{x,v})]\) 容斥掉 \(u,v\) 属于同一棵分治子树的。

\(x\) 开始遍历每个点,维护 \(str_{u,x}\) 在 SAM 上的点,将其标记一次。

\(lst_{p}\) 表示 \(T[1:p]\) 在 SAM 上的点,\(num_p\) 表示 SAM 上的点 \(p\) 被标记的次数,则 \(\sum_u[p\in rpos(str_{u,x})]\) 即为 \(lst_p\) 沿 parent 树到根路径上 \(num\) 之和。对于 \([p\in lpos]\) 在反串 SAM 上标记即可。

怎么维护 SAM 在字符串前添加一个字符?

\(R[x]\) 表示 SAM 上 \(x\) 节点的 \(endpos\) 集合中的任意一个值,\(son[x][c]\) 表示 \(x\) 节点对应长为 \(len[x]\) 的字符串前添加字符 \(c\) 所对应的节点,有 \(son[fa[x]\ ]\ [\ T[\ R[x]-len[fa[x]]\ ]\ ]=x\)

对于在 \(S\) 前添加字符 \(c\):设 \(S\) 当前对应节点 \(v\)

  • \(|S|<len[v]\),如果 \(c=T[R[v]-|S|]\) 则对应 \(v\),否则为不存在。

  • \(|S|=len[v]\),如果 \(son[v][c]\) 存在则对应 \(son[v][c]\),否则为不存在。

单次复杂度 \(m+siz_x\)。总复杂度 \(O(n\log n+nm)\) 显然不对。

显然对于任意连通块有 \(O(siz^2)\) 的暴力找出所有 \(str_{u,v}\) 询问 \(endpos\) 大小,没有容斥且做完之后不需要继续向下点分治。所以考虑根号分治对小的跑暴力,大的运行上述算法。

注意如果 \(siz_x\) 大但其要容斥的子树 \(siz_v\) 小则在容斥时要跑暴力算法,否则容易用菊花图卡掉。

设两算法的阈值为 \(B\),算法一复杂度是 \(B^2\times \frac n B=nB\),算法二是 \(m\times \frac n B=\frac{nm} B\),平衡为 \(O(n\sqrt n)\)

posted @ 2025-07-04 15:33  programmingysx  阅读(49)  评论(0)    收藏  举报
Title