ARC104 (D~F) 简要题解
ARC104 (D~F) 简要题解
这场出题人应该很擅长计数,尤其是不重不漏的按方案计数。
Multiset Mean
元素范围为 \(1 \to n\),每个元素最多出现 k 次,对于所有可能的集合,求出其平均数,问对于任意 \(i \in [1,n]\) 作为平均数的方案数事多少。
\(1 \le n,k \le 100\)
肯定是个 dp 题,首先枚举平均数 V,设 \(f[x][y]\) 表示用 \(1 \sim x\),拼出来总和为 y 的方案数(每个数 x 改成 \(x - V\),最后考虑和为 0 即可),转移 \(f[x][y] = \sum f[x-1][y-kx]\),用前缀和优化一下即可做到 \(\Theta(n^4)\),但这咋求平均数。
发现对于 x 事平均数的方案,对于小于 x 的事 \((x-1),(x-2),(x-3)\cdots\),大于的事 \((x+1),(x+2)\cdots\)
让集合中的每个元素都减 x,则最终集合的和是 0 则 x 就是平均数,所以考虑正负贡献分别考虑,小于 x 的贡献是 \(-1 \to -(x-1)\) 的,大于 x 的贡献是 \(1 \to n-x\) 的,所以就是小于的凑出一个数 -t,大于的凑出一个数 t,这样就行了。
另外发现第二维可以缩小范围达到 \(125000\) 左右来优化常数。
Random LIS
神仙题。
考虑我们的最终序列,将它按 \(a_i\) 排序使它的最长上升子序列等于排序后 id 的最长上升子序列。
那么优先比较 \(a_i\),然后 id 大的放前面,这样转化后的排列最长上升子序列长度就是固定的了。
枚举全排列,让 \(a_i\) 不降,其中的限制是 \(a_i (\le,<) a_{i+1}\),如果 \(id_i > id_{i+1}\),那么有等号,否则没有。
我们考虑把所有的小于号变成小于等于,显然直接把后面的减一即可。
所以现在就是从点 (1, 1) 开始到 \((n+1,\infty)\) 的方案数,这个可以容斥求的。
最终复杂度 \(\Theta(n!\times n^3)\)
Visibility Sequence
容易发现每个位置的取值并不重要,重要的事它们的相对顺序,所以高度就变成 \(\Theta(n)\) 级别的了。
考虑每个位置事哪些位置的控制点,我们令 0 处有一个 \(\infty\) 高度的楼,令每个位置向前一个 \(H_j > H_i\) 的位置 j 连边,这样你就发现每个位置的子树是一个原序列上的区间。
我们考虑让序列 P 和 H 建立起一一映射的关系。因为有 \(X_i\) 的限制,所以我们让 \(H_i\) 尽可能小。
容易发现,对于一种已确定的 P,那么就可以建出树来,左兄弟的 H 一定小于等于自己,父亲的 H 一定大于自己,孩子们的 H 一定小于自己。因此不难确定 \(H_i=\max\{H_s+1,H_b\}\),每个 P 都对应着一个 H,也很好构造每个合法的 H 对应着一个 P。
因此我们有了区间 dp 的想法,设 \(f[l][r][h]\) 表示在区间 \([l,r]\) 中,l 作为根,高度为 h 的方案数,有
前缀和优化即可。
const int P = 1e9 + 7;
const int N = 105;
ll f[N][N][N], s[N][N][N], X[N], n;
int main() {
read(n); X[1] = ++n;
for (int i = 2;i <= n; i++) read(X[i]);
for (int i = n;i >= 1; i--) {
f[i][i][1] = 1;
for (int j = 1;j <= min(X[i], n); j++) s[i][i][j] = 1;
for (int j = i + 1;j <= n; j++) {
for (int x = 2;x <= min(X[i], n); x++) {
ll res = 0;
for (int t = i + 1;t <= j; t++) if (X[t] >= x - 1)
res = (res + s[i][t-1][x] * f[t][j][x-1] + s[t][j][x-2] * f[i][t-1][x]) % P;
s[i][j][x] = ((f[i][j][x] = res) + s[i][j][x-1]) % P;
}
}
}
write(s[1][n][n]);
return 0;
}