题意
做法
令(f_S)为原状态为(S)的答案
令(g_S=sumlimits_{Ssubseteq T} f_T)
我们求({g_S}),最后(O(n^22^n))子集反演回({f_S})
考虑(g_S)的意义,即为钦定一些大小固定的链,然后随意拼接起来
比如(11010100),是钦定大小为({3,2,2,1,1})的链
对于钦定的集合相同的(S_1,S_2),(g_{S_1}=g_{S_2})
故本质不同的状态为(O(P(n)))((P(n))为(n)的拆分方案数)
令(h_{S})为集合(S)的链个数(哈密顿路径个数),可以简单(O(n^22^n))求得
对于一种拆分方案,我们要做的是子集卷积,不过这样复杂度是(O(P(n)cdot ncdot n^22^n))的
我们可以将拆分数的搜索建出一棵搜索树,然后节点与节点之间的转移用子集卷积,最后再叶子节点即可得到答案
具体讲下细节
一般在搜索拆分数时,我们习惯从小到大搜数,这样会导致许多无效搜索
为了方便代码的实现,我们从大到小搜数,这样均为有效搜索
时间复杂度(O(P(n)2^n+n^22^n))