2022 CSP-S2 T3 的数据构造方法讨论总结
重要当事人已同意公开部分讨论内容。
感谢 @LittleYang0531 , @八云蓝 , @minstdfx , @sszcdjr , @_FLAMEs_ , @Read_int , @_998344353_ , @bdfs_then_csdn , @cinccout , @The_Endd , @纳西妲 等人的协助。
大致按照介入时间排序,且 ID 为我的最深印象 ID,若有其他更合适的写法,可以提出,我会修改。
向那些排除万难造出合格高强度数据的工作者和 OIers 致敬。
大纲
讨论时间:约 \(2h\);
讨论结果:感觉较为成功,理论较为到位,只差实现;
原题:[CSP-S 2022] 星战(洛谷 比赛链接),在 洛谷比赛 #90216 [CSP-S 2022 自测] 中;
或者使用直达链接:P8819 [CSP-S 2022] 星战,需要比赛结束后才能成功打开。
数据构造总思路:若操作后,图为一个「内向基环树森林」,则输出为 YES
,否则为 NO
。
数据构造困难:保证有相当数量的 \(2\)、\(4\) 操作之后可以保证为内向基环树森林,卡掉暴力和乱搞。
讨论得到的一些的方法
1 暴力枚举操作
思路:暴力枚举生成数据
大致内容:
在每个 \(1\)、\(3\) 操作之后记录状态,在每个点都跑一下 \(2\)、\(4\) 操作,如果是内向基环树森林就造出来一个合格的 \(2\)、\(4\) 操作;并且分配少量 \(1\)、\(3\) 操作后为 YES
的结果和一部分操作之后为 NO
的结果。
优点:\(2\)、\(4\) 操作可以出现 YES
的次数比较多;缺点:耗时特别长,你不仅要判定是不是内向基环树森林还要进行大量循环。等着跑一晚上甚至一天两天吧。
2 操作无效化
思路:投机取巧生成数据
大致内容:
如果是一个内向基环树森林,进行一次失效的 \(2\)、\(4\) 操作,应该还是内向基环树森林。
缺点显然:数据会很水,会滋生大量假做法。
3 反向操作连接合法基环树森林状态,生成合理数据
思路:反向操作生成数据
将给定的四种操作反向,反向操作规则如下:
操作 \(1\):修复指定虫洞(原本为摧毁指定虫洞);
操作 \(2\):修复被摧毁的一部分连接指定据点的虫洞,需要指定据点可以摧毁的所有虫洞都被摧毁(原本为摧毁所有能够摧毁的连接指定据点的虫洞);
操作 \(3\):摧毁指定虫洞(原本为修复指定虫洞);
操作 \(4\):摧毁被修复的一部分连接指定据点的虫洞,需要指定据点的所有虫洞都完好(原本为修复所有被摧毁的连接指定据点的虫洞)。
这样可以使得反向操作后的状态正向操作后可以恢复成反向操作前的状态。
上述内容为概要,接下来具体的填充部分有如下演变:
v1 随机合法状态,通过操作实现新合法状态
做法:
首先随机出来一个 YES
的状态;
接下来重复执行「进行一次 \(2\) 操作或 \(4\) 操作,接下来完成一些 \(1\)、\(3\) 操作以及少量 \(2\)、\(4\) 操作变回 YES
的状态」直到操作个数接近给定上限;
最后在这个之上再进行一些简单的操作,使得起始和终止可以为 NO
的状态,使得操作数与给定上限相差无几。
困难:方法不好实现,「随机出来一个内向基环树森林之后经过少量改动变成另一个内向基环树森林」较难做到。
v2 随机大量合法状态,整理顺序,通过操作实现下一个合法状态
做法:
将随机出来「一个」YES
的状态变成「\(n\) 个」,较强的数据 \(n\) 大概可以设定为 \(1000\) 甚至更大,\(1000\) 本身已经很大了;
进行相似度匹配(定义:两个图的相似度 为 一个图要变成另一个图进行加边减边的操作次数),并把更相似的结合到一起,以在增加合法个数时尽可能降低操作次数;
接下来进行操作,先枚举一波可以进行反向 \(2\)、\(4\) 操作且操作影响到变动的边的点,看操作之后是更优还是更劣,尽可能选取更多的不冲突的点进行操作,之后剩下的点用反向 \(1\)、\(3\) 操作实现。这些操作用来连接各个合格状态。
若有剩余操作次数则可以再进行一些简单的操作,使得起始和终止可以为 NO
的状态,使得操作数与给定上限相差无几;否则可以适当减少,可以接受的范围大概为 \(90\%n\) 个合法状态以上,或者 \(95\%n\) 个合法状态以上。
其中相似度匹配又有了两种方案:
v2.1 相似度阈值以下停止比对直接通过
我们假定把阈值设定为 \(30\),相似度在 \(30\) 以下的时候停止比对其他状态,即使有一个后面的图相似度仅为 \(10\) 也停止比对;然后继续比对下一个状态。
缺点:不是最优;优点:可以大量节省时间。
为了弥补不是最优的缺点做了一个小优化:比对出第 \(n+2\) 个图之后,将第 \(n\) 个图和第 \(n+2\) 个进行比对,可能会更优。
v2.2 匹配最小相似度(找最相似)
暴力循环匹配所有图,并制定状态图的出现顺序使得相似度之和(总操作次数)最小。
4 特殊图构造法
在 \(2\)、\(4\) 操作的时候可以记录某些边的状态来进行有限的更新,所以如果 \(2\)、\(4\) 操作涉及的边数少了就会导致数据变水,可能不能一条条地修改边的更新状态。
所以一种新构想诞生了。
特殊图构造:
选出大概 \(\sqrt{n}\) 个关键点,在 \(\sqrt{n}\) 个关键点中间会有一个中心点,剩下的关键点就全部连在一个中心点上,关键点之间可以随意连边,形成一个三层树高然后一二层的节点可以任意连边的图,保证了数据的强度。
\(2\)、\(4\) 操作期望修改一个关键点所需要的时间是 \(\sqrt{n}\) 的。
操作:
- 先从初始状态主要用 \(1\)、\(3\) 操作到一个合法的状态
- 转移到另一个合法状态:
(1) 随便进行一些 \(2\)、\(4\) 操作;
(2) 查找没有和子节点连上边的点使用 \(4\) 操作连边;
(3) 用 \(1\)、\(3\) 操作补齐一二层之间的边。
期望修改次数是两层节点之间边数 \(+\ \sqrt{n}\)。
优点显然:很好处理,强度不低;缺陷:可能识别出来(虽然说考场上也不是很容易识别罢了)。
最后被认可的两种方法(完整版)
方法 3:反向操作构造法
将给定的四种操作反向,反向操作规则如下:
操作 \(1\):修复指定虫洞(原本为摧毁指定虫洞);
操作 \(2\):修复被摧毁的一部分连接指定据点的虫洞,需要指定据点可以摧毁的所有虫洞都被摧毁(原本为摧毁所有能够摧毁的连接指定据点的虫洞);
操作 \(3\):摧毁指定虫洞(原本为修复指定虫洞);
操作 \(4\):摧毁被修复的一部分连接指定据点的虫洞,需要指定据点的所有虫洞都完好(原本为修复所有被摧毁的连接指定据点的虫洞)。
使得反向操作后的状态正向操作后可以恢复成反向操作前的状态。
- 保证
YES
个数:随机出来 \(n\) 个内向基环树森林(例如说 \(1000\) 个); - 分配操作次数使得不超限:进行相似度匹配(定义:两个图的相似度 为 一个图要变成另一个图进行加边减边的操作次数),并把更相似的结合到一起;
- 连接合格状态:进行操作,先枚举一波可以进行反向 \(2\)、\(4\) 操作且操作影响到变动的边的点,看操作之后是更优还是更劣,尽可能选取更多的不冲突的点进行操作,之后剩下的点用反向 \(1\)、\(3\) 操作实现。
- 弹性收尾工作:若有剩余操作次数则可以再进行一些简单的操作,使得起始和终止可以为
NO
的状态,使得操作数与给定上限相差无几;否则可以适当减少,可以接受的范围大概为 \(90\%n\) 个合法状态以上,或者 \(95\%n\) 个合法状态以上。
得到 YES
的个数主要取决于操作次数的分配方法。
方法 4:特殊图构造法
特殊图构造:选出大概 \(\sqrt{n}\) 个关键点,在 \(\sqrt{n}\) 个关键点中间会有一个中心点,剩下的关键点就全部连在一个中心点上,关键点之间可以随意连边,形成一个三层树高然后一二层的节点可以任意连边的图,保证了数据的强度。
操作:
- 先从初始状态主要用 \(1\)、\(3\) 操作到一个合法的状态
- 转移到另一个合法状态:
(1) 随便进行一些 \(2\)、\(4\) 操作;
(2) 查找没有和子节点连上边的点使用 \(4\) 操作连边;
(3) 用 \(1\)、\(3\) 操作补齐一二层之间的边。
期望修改次数是两层节点之间边数 \(+\ \sqrt{n}\),\(n\) 为 \(5\times10^5\) 时大约是 \(707\) 个 YES
。
杂项
以及感谢一些建议:
「但是同时你得结合菊花图啥的,要不然你咋卡暴力,信奥中的图可大多都是稀疏图」
「带花树森林构造法好一点吧,然后还要分花操作防止离线多判(),然后加边一下」
后面会考虑的,万分感谢。
以及欢迎提出更多建议与意见。