jiangly CSP2020模拟赛 部分题解

T3

思路:按位分治

大概就是从高到低考虑二进制的每一位

(solve(S,i))表示当前我们考虑在(S)这个集合中选,当前只需要考虑只取出第(i)位及以下的限制(x),满足题意的方案数

那么对限制的第(i)位,我们把(S)中第(i)位是(1)和是(0)的分成两个集合(A)(B)

接下来讨论

如果限制的这一位是(1)的的话,我们显然只能在(A)(B)中各至多选择一个,否则异或出来必然存在这一位是(0)

那么此时我们就满足了(x)(i)位的限制

于是这一个我们可以考虑对(A)建一棵trie,对(B)中的每一个数在trie数上统计满足(x)的后(i-1)位的方案数,这一部分总复杂度是(O(nlog a_i))

如果限制的这一位是(0)的的话,我们从两个集合中各拉出来一个数异或起来显然是(>=x)的,所以只需要考虑A和B内部的选择,我们发现这变成了两个子问题(solve(A,i-1)) (solve(B,i-1))的答案的积

我们发现总共分治(log a_i)层,每层总个数不超过(n),所以这部分总复杂度也是(O(nlog a_i))

总复杂度(O(nlog a_i))


T4

思路:容斥

我们考虑把每个(k)的答案分开来计算

首先我们发现,对于操作次数为(k)的答案是所有最长上升子串长度至少是(n-k)的排列的个数

这一点不难证明,此处略去

我们考虑用总排列数减去所有不含长度至少是(n-k)的上升子串的方案数

这一部分我们可以考虑容斥,用总方案数减去钦定了一个长度是(n-k)的上升子串的方案,再加上两个(n-k)的上升子串的方案数....

但是我们注意到多个重叠的上升子串是需要合并的

于是我们就可以把长度为(x)的上升子串的所有能够构成他的方案的容斥系数求出来,这里我们认为不属于任意一个上升子串的单个数,其长度是(1)

然后这里可以dp,大概就是

(f[1]=1 f[n-k]=-1)

(f[i]=-sum_{j=1}^{n-k-1}f[i-j])

得到这个以后就可以计算了

我们设(g[i])表示总长度是i的所有排列方案的容斥系数总和

那么(g[i]=sum_{j=1}^{i}g[i-j]f[j])

但是我们还要给每一个上升子串分配他是哪些数怎么搞

我们发现分配方案恰为(frac{n!}{prod a_i!})其中(a_i)是我们钦定的每一个上升子串的长度

(n!)可以提出来,(a_i!)这个东西是可以揉到容斥系数里的,即对于dp出来的(f_i)都乘上(frac{1}{i!})

单次dp复杂度是(O(n^2)),总复杂度是(O(n^3))

过不了怎么办?

我们把dp出来的(f[i])打出来,发现一个惊人的事情!

对于(i=(n-k)*t)(f[i])(-1)

对于(i=(n-k)*t+1)(f[i])(1)

其他的都是(0)

其实这一点非常好证,此处略去

于是我们的转移只有(n/(n-k))

单次dp复杂度降至(O(frac{n^2}{n-k})),总复杂度降至(O(n^2ln n))

原文地址:https://www.cnblogs.com/deaf/p/13804783.html