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(n\log a_i)\)

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

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

总复杂度\(O(n\log 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^2\ln n)\)

posted @ 2020-10-12 19:36  deaf  阅读(1662)  评论(0编辑  收藏  举报