CF div3 998(F,G)

F

dp + 组合数学

需要注意,数组中>1的数字个数不会超过log2k个。

先暂时不考虑1的摆放,只考虑所有>1的数:

fl,i长度为l,乘积为i,且所有元素均>1的数组个数

考虑数组的最后一个元素d,必有d|i成立,因为每个元素一定是i的因子。

fl,i可以由fl1,i/d递推而来:

fl,i=d|ifl1,i/d

ansi表示乘积为i,长度取值范围[1,T]的数组个数,则:

ansi=l=1Tfl,i

其中T<=log2k,可以直接暴力计算得到。

现在需要考虑将数字1加入到数组中。设加入了j1,则新数组的长度为l+jj可能取值范围是[0,nl]。加入j1后的方案数还需要考虑>1l个数在l+j个位置中的哪些位置。

ansi表达式变为:

ansi=l=1T(fl,ij=0nlCl+jl)

其中j=0nlCl+jl这部分枚举计算的复杂度为O(n),不可接受。故考虑优化:

由公式:

len=lnClenl=Cn+1l+1

故上式改写为:

ansi=l=1T(fl,iCn+1l+1)

其中T不会超过log2k,故复杂度不会与n有关,只与k有关。

计算Cn+1l+1:不能直接用逆元法来求,因为n很大,不能预处理。考虑到l<=logk,故可以直接根据组合数的定义式,暴力枚举l来求所有的 Cn+1l+1。(详细见代码)

复杂度分析:主要在于递推f数组的过程。枚举数组的乘积是谁O(k),计算因子数量O(k),枚举数组长度O(logk),故总复杂度为O(kklogk)

关于公式len=lnClenl=Cn+1l+1的证明:

len=lnClenl=Cll+Cl+1l+...+Cnl

Cll 改为 Cl+1l+1,由公式 Cnm=Cn1m+Cn1m1 每次计算前两项,最终就只剩一项,即 Cn+1l+1

code

G

思维 + dp

首先显然可以发现:任意一列的两个数一定是绑定在一起的,比如(a,b)在同一列,则不管怎样操作,(a,b)始终都会在同一列。

那么,最终形成的序列一定满足该性质:对于所有列,按每一列中的最小值升序排序,证明略。

同时,可以发现某一种交换方式,使得任意两列可以交换,并且不改变任何一列内数的上下关系,如下图:

pEkH5m4.png

根据以上两点就可以发现:将原序列按列的最小值升序排序后的合法性,与检查原序列的合法性是等价的。

因为可以交换任意列,所以总是可以将原序列变为按最小值升序排序的序列,而同时所有列按最小值升序排序又是满足合法性的必要条件,因此得证。

那么剩下的问题就转变为了检查上下数交换的合法性。由下图的操作可以发现,也可以同时交换任意两列的上下两个数:

pEkbEjS.png

所以上下数交换的次数一定是偶数。

考虑dp

dp[i][0/1][0/1]:考虑前i列,总交换次数为j(只需要考虑奇偶性,0为偶数次,1为奇数次),且第i列交换了k次(同j,即相当于第i列是否翻转)来使得前i列有序,是否可行。

initdp[0][0][0]=1

ans=dp[n][0][0]||dp[n][0][1](总交换次数只要是偶数次就合法)

转移:由于已经保证了前i1列有序,故要保证前i列有序,只需要保证第i1列与第i列之间有序即可。枚举第i1列和第i列的所有状态(是否翻转),通过检查是否满足两列有序来决定是否转移。具体转移细节见代码。

code

posted @   jxs123  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示
主题色彩