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)\)