二月——Week2
2025.2.10
A: 数方题
因为任意两行或两列都可以随意交换,所以可以先选择 \(A\) 中的一列将那一列排为升序,之后枚举 \(B\) 的每一列,同样排为升序。
这样之后就不能对行进行交换了,再将剩下的 \(n-1\) 列按第一行的数字进行排序看两个矩阵是否相同就可以了。
B: 数环题
通过 B 性质基本就能推出正解了。
B 性质是没有初始边,点连向每个点的概率都相同,这时候我们可以直接枚举环长,答案就是 \(\sum\limits_{i=1}^{n}A_{n-1}^{i-1}(\frac{1}{n})^i\)。
正解与之类似,将初始边先建出来,形成若干个连通块。
最后我们求每个点,其实就是往他上面拼连通块。
对于成环的连通块,拼上去会让概率变成零,所以直接跳过。
剩下的连通块,连向每个连通块的概率为当前连通块所有点的概率之和。
之后直接做 01 背包就可以了,查询每个点时先把那个点所在连通块撤销掉。
2025.2.11
A:钥匙
半个小时想出来了,比较简单。
考虑一个限制 \(a_ix+b_iy<c_i\) 其实就是限制了一个半平面,所以找出给定的点的凸包,使用叉积计算凸多边形面积,看计算出来的面积和使用 Pick 定理计算出来的相不相同,特判一个点和一个直线。
B:排列蛤蟆
题目的限制其实就是限制循环移位前后排列的逆序对数不变。
大胆猜想如果两个排列的逆序对数相同,那么最终一定可以变得相同。
具体方案如何求?
首先操作是可逆的,所以我们可以对两个排列同时操作。
一个比较直接的想法是将 n 都移到最右边,这样就可以递归下去变成子问题。
求方案比较困难,不过判断最终能否相同的结论还是比较好猜的。
C:神奇的跑鞋
\(t=2\) 的时候,一个点对的代价和网格图相同,当且仅当一个点在树上的路径均为网格图上靠近另一个点的路径,所以给边定向,计算左上到右下和左下到右上这两个对角线的方案数,再减去只上下和只左右的方案数就是答案。
\(t=1\) 的时候判断这 \(n\) 个点的哈密顿回路长度是否和网格图上这 \(n\) 个点的哈密顿回路长度相同,一个结论是只需要判断两两之间的路径是否和原网格图上路径长度相同,感觉比较有用,希望能记住。
2025.2.12
A:道路
竞赛图三元环计数,摆个结论:\(\binom n2-\sum\limits_{i=1}^{n}\binom {out_i}{2}\)。
理解起来比较简单,三元环一定有且仅有一个点出度为 2,用总的减去不合法的就可以了。
赛时把结论忘了对着三个点形成的八个图试了一个小时才试出来一种能容斥出答案的容斥方式。
有了结论之后,对于进行的 \(m\) 次操作就可以扫描线同时用线段树维护了。
B:图图
题目给定的限制方式看起来像是一般图最大权匹配的样子,不会!
发现 \(k\) 其实比较小,所以将图随机黑白染色,之后跑二分图最大权匹配的正确率是 \(\frac{1}{2^k}\),跑 \(K\) 次的错误率为 \((1-\frac{1}{2^k})^K\),跑大概 5000+ 次正确率就比较高了。
但是这种东西为啥每次碰到都想不到啊,以后答案用到的决策比较少的一定要考虑随机。
2025.2.13
A: 半城烟沙
每次发生合并一定是两个矩形的合并,而每次合并,矩形个数会至少减少一个,所以如果实现较好,时间复杂度是 \(O(n\log n)\) 的。
问题是如何实现?
赛时写的从每个点开始向右扩展直至不能扩展,但是矩形的合并并不总是从左向右的,所以这显然是错误的。然后突然意识到快速找出要发生合并的矩形,并且快速找出已经被覆盖的矩形并把它删除是比较困难的,最后都没想出来如何维护这个东西。
赛后发现是我肤浅了,把初始的点先按 \(y\) 排序之后对 \(y\) 进行扫描线,同时用线段树维护 \(x\) 轴的区间内最大的 \(y\)。
这样对于每个点我们只需要一直向前合并直至不能合并就好了,时间复杂度 \(O(n\log n)\)。
如果二维平面向四周合并或者一维直线向两端合并都可以尝试先排序之后扫描线暴力向前合并。
B:神明的迷思
碰到一个题,要先冷静的分析。
本题有两个性质,设 \(f(x)\) 为从 \(x\) 开始执行一轮操作序列最终停留的位置,如果没有撞墙操作,那么 \(f(y)-f(x)=y-x\)。
而撞墙操作也并不会改变 \(f(x)\) 的大小关系,所以 \(f(x)\) 单调不降,同理可得 \(f(x)-x\) 单调不增。
对于 \(f(x)\le x\) 的情况,我们直接以 \(x\) 为起点 dp 求出。
对于 \(f(x)>x\) 的情况,以 \(x\) 为起点 dp 求出来的同时包含合法和不合法的操作序列,不可行。我们知道若操作序列合法,那么它最后一定会停留在后面某个 \(f(x)=x\) 的地方,考虑在那个位置统计。但是如果 \(f(x)=x\) 的地方有多个就被算重,所以我们钦定在最左侧的 \(f(x)=x\) 的位置统计,而既然是最左侧的满足 \(f(x)=x\) 的位置,那么它的路径一定恰好经过 \(1\) 且没有撞墙,所以我们 dp 的同时记录一下有没有经过 \(1\) 就好。
2025.2.14
A: 名もなき何もかも/皆无其名
赛时想到了容斥,处于迷信我坚定的认为这一定能到正解。但实际上既不能扩展成正解而且还挂掉了。
树上放关键点问题,考虑树形 dp 。
设 \(f_{x,i}\) 代表 \(x\) 子树内的点均已满足,且据 \(x\) 最近的点的距离为 \(i\) 的方案数,\(g_{x,i}\) 为 \(x\) 子树内存在点未被满足,要求 \(x\) 子树外和 \(x\) 距离 \(\le i\) 的方案数。
合并如下
点击查看代码
void D(int x,int fa)
{
if (!del[x]) f[x][0] = 1;
g[x][r[x]] = 1;
for (int i = las[x],y;i;i = e[i].pre)
{
if ((y = e[i].to) != fa)
{
D(y,x);
for (auto [a,b] : f[x])
{
for (auto [c,d] : f[y]) F[min(a,c+1)] = (F[min(a,c+1)]+b*d)%P;
for (auto [c,d] : g[y])
{
if (a <= c-1) F[a] = (F[a]+b*d)%P;
else G[c-1] = (G[c-1]+b*d)%P;
}
}
for (auto [a,b] : g[x])
{
for (auto [c,d] : f[y])
{
if (c+1 <= a) F[c+1] = (F[c+1]+b*d)%P;
else G[a] = (G[a]+b*d)%P;
}
for (auto [c,d] : g[y]) G[min(a,c-1)] = (G[min(a,c-1)]+b*d)%P;
}
f[x] = F,g[x] = G;
unordered_map < int,LL > tmp1,tmp2;
swap(tmp1,f[y]),swap(tmp2,g[y]),F.clear(),G.clear();
}
}
}
遇到树上放关键点问题一定要考虑树形 dp,设出 \(f\) 和 \(g\) 来求答案,拜托!!!
B: 傷つき傷つけ痛くて辛い/受伤
把左右部点分别分为黑白两部分,发现最后的操作一定形成若干条链和若干个环。
给边定向为同色从左向右,异色从右向左之后,就能跑带负圈的费用流了。
求具体方案可以先把所有的环找出来,再把所有的链找出来,写起来比较麻烦。
C: 運命の華/命运之花
记一下场上没写出来的 \(O(n^2)\) dp 部分分。
首先可以 \(O(n^2)\) 预处理出来一个区间的周期串长度及其周期,然后 \(O(n^2)\) dp。
但是这里一个非常困难的点在于只有极长相等连续段才能造成贡献,赛时在这里卡死了。
想不出来比较优秀的 dp 状态和方式来完成去重的话,那么我们可以考虑容斥。
设 \(F=\sum\limits_{i=0}^{\infty}ix^i\),那么容斥系数的生成函数 \(G\) 满足 \(F=G\times(F+1)\)。
那么 \(G=\frac{F}{F+1}\)。我们可以容易地求出 \(G\) 的封闭形式,但是从封闭形式还原到生成函数似乎非常困难。
所以放弃封闭形式的推导,直接写一个多项式乘法逆,最后发现我们的 \(G\) 是 \(0,1,1,0,-1,-1\) 的循环。
这种极长连续段做贡献的一定要考虑容斥!!!
不过容斥系数的推导可能有时候比较困难,也许运气好可以手玩出来吧,赛时没想出来也算正常。
2025.2.15
A: average F. Doremy's Average Tree
正解不会,说一下能过原题的 \(O(n^2)\) 做法。
我们肯定是贪心的从 \(1\) 到 \(n\) 确定字典序。对于当前点 \(i\) 我们要选不影响 \([1,i-1]\) 的取值且使 \(i\) 的取值最小的那个节点。
但是这样的结点可能会存在多个,所以我们优先选深度最浅的那个节点,因为这样满足当前最优且次数最少,唯一的问题的可能不满足后续最优。
而不满足后续最优的时候我们只需要看一看是否能反悔就行了。
思路不算太难,不过实现起来头脑不清醒的话会写的比较恶心。
B: color Shortest Path Query
设 \(f_{i,j}\) 代表走到 \(i\) 点经过 \(j\) 条黑边最少要经过多少条白边。
由于答案是 \(a\times x+b\times y\) 的形式,所以只有下凸壳上的点是有用的。
而根据 Link ,值域为 \(n\) 的整点凸包的点数最多为 \(O(n^\frac{2}{3})\)。
所以我们只维护凸包上的点,dp 转移时合并两个凸包,时间复杂度 \(O(mn^\frac{2}{3})\)。
碰到 \(ax+by\) 的形式一定要想到凸包!
C: sensor 踩气球
当一个位置 \(p\) 由 \(1\) 变为 \(0\),如下图:
发现是将满足 \(i<l\le j\land p\le r<k\) 或者 \(j<l\le p\land k\le r<q\) 的区间加入,同时将 \(j<l\le p\land p\le r<k\) 的区间删去。
每个区间只会被加入一次,所以可以树套树快速找出这样的区间,时间复杂度 \(O(n\log^2n)\)。
上述做法比较劣,但是发现本题将输入的区间按右端点从小到大排好序后相当于没有插入和删除操作,可以在线段树每个节点上套上常数较小的 vector 来维护,跑的已经和 \(O(n\log n)\) 的做法一样快了。
不过上述做法没有什么思维含量,这里说一下正解。
把每个区间在线段树上拆成 \(\log n\) 个区间,当线段树某个结点维护的区间被删为 \(0\) 或 \(1\) 时,我们就暴力更新一下拆分到当前节点的区间,时间复杂度 \(O(n\log n)\)。
2025.2.16
A:矩阵
记录一下三十分部分分,感觉是有意义的。
我们如果知道了进行 \(k\) 次操作后每个数是由哪几个数异或而来,就可以直接高斯消元来解异或方程。
所以对每个数执行一遍 \(O(2^nmk)\) 的模拟,就能得知是由哪几个数异或而来。
B:修公路
给出一个 \(2n\) 个点的圆上的 \(n\) 条不在端点处相交的弦,若两条弦相交,则认定这两条弦联通,求连通块数量。
把环断成 \([1,2n]\) 的链,一个区间内的点是一个连通块的必要条件时这个区间的点数等于当前区间的颜色数乘二,虽然并不充分,但是并不影响我们的答案。点数等于颜色数乘二比较难办,这时候换个角度,我们使用异或哈希,若一个区间异或和为 0,也就代表点数等于颜色数乘二。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现