+ 组合数学
需要注意,数组中的数字个数不会超过个。
先暂时不考虑的摆放,只考虑所有的数:
设长度为,乘积为,且所有元素均的数组个数
考虑数组的最后一个元素,必有成立,因为每个元素一定是的因子。
则可以由递推而来:
设表示乘积为,长度取值范围的数组个数,则:
其中,可以直接暴力计算得到。
现在需要考虑将数字加入到数组中。设加入了个,则新数组的长度为,可能取值范围是。加入个后的方案数还需要考虑的个数在个位置中的哪些位置。
则表达式变为:
其中这部分枚举计算的复杂度为,不可接受。故考虑优化:
由公式:
故上式改写为:
其中不会超过,故复杂度不会与有关,只与有关。
计算:不能直接用逆元法来求,因为很大,不能预处理。考虑到,故可以直接根据组合数的定义式,暴力枚举来求所有的 。(详细见代码)
复杂度分析:主要在于递推数组的过程。枚举数组的乘积是谁,计算因子数量,枚举数组长度,故总复杂度为。
关于公式的证明:
将 改为 ,由公式 每次计算前两项,最终就只剩一项,即 。
code
思维 +
首先显然可以发现:任意一列的两个数一定是绑定在一起的,比如在同一列,则不管怎样操作,始终都会在同一列。
那么,最终形成的序列一定满足该性质:对于所有列,按每一列中的最小值升序排序,证明略。
同时,可以发现某一种交换方式,使得任意两列可以交换,并且不改变任何一列内数的上下关系,如下图:

根据以上两点就可以发现:将原序列按列的最小值升序排序后的合法性,与检查原序列的合法性是等价的。
因为可以交换任意列,所以总是可以将原序列变为按最小值升序排序的序列,而同时所有列按最小值升序排序又是满足合法性的必要条件,因此得证。
那么剩下的问题就转变为了检查上下数交换的合法性。由下图的操作可以发现,也可以同时交换任意两列的上下两个数:

所以上下数交换的次数一定是偶数。
考虑:
:考虑前列,总交换次数为(只需要考虑奇偶性,为偶数次,为奇数次),且第列交换了次(同,即相当于第列是否翻转)来使得前列有序,是否可行。
(总交换次数只要是偶数次就合法)
转移:由于已经保证了前列有序,故要保证前列有序,只需要保证第列与第列之间有序即可。枚举第列和第列的所有状态(是否翻转),通过检查是否满足两列有序来决定是否转移。具体转移细节见代码。
code
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战