题解:AT_dwacon6th_prelims_e Span Covering
题意:很简单了,不再赘述。
做法:
为了方便这里的数轴是 \([1,X]\)。
要求每个地方都被覆盖这个东西很难满足,或者说这是个很经典的容斥,就等于我们容斥有至少有哪些位置不满足,然后我们就可以把这些区间随便扔进去,考虑对于一个区间长度为 \(i\) 的,假设容斥不能放置的位置后,中间其中一个连续的可以放置段长度为 \(j\),那么方案数就应该是 \(\max(j-i+1,0)\)。
因为对于相同的连续段长度和覆盖区间的长度,所以我们记 \(x_i\) 为覆盖区间长度为 \(i\) 的有多少个,\(c_i\) 代表对于一种容斥情况,连续的可放置段长度为 \(i\) 的有多少个。
那么这种情况的方案数就应该是:
然后我们对于相同的 \(c\) 的情况,我们考虑去分配这些段,还要乘上容斥系数,方案数是:
解释一下,第一个是我给这些段定序,第二个组合数是我们现在加上 \(0,X+1\) 这两个划分点,中间一共有 \(X-\sum\limits_{i=1}^X ic_i+1\) 个空隙,然后每个空隙间只能最多放一个区间进去,所以是这个东西,最后一个就是有一个划分点,容斥系数乘上 \(-1\)。
把上面这两个东西乘在一起就是对于一种 \(c\) 的答案。
然后我们考虑怎么计算所有的 \(c\),我们看我们需要在计算的时候记录什么,首先肯定是需要 \(\sum c_i\) 和 \(\sum ic_i\) 的。但是前面这个 \(\prod\limits_{i=1}^X(\sum\limits_{j=i}^Xc_j(j-i+1))^{x_i}\) 怎么计算?
我们发现,其实 \(\sum\limits_{j=i}^Xc_j(j-i+1))\) 这个东西,如果我们从后往前做 dp,就等于我们 dp 完 \(i\) 之后,对于每个 dp 值再乘上当前的 \(\sum{ic_i}-i\sum c_i\)!所以我们本质上就只用记录着两个东西就可以进行 dp 了。
然后对于 \(c_i!\) 这些东西可以直接在 dp 时统计贡献。
复杂度的话,枚举 \(i,\sum ic_i,\sum c_i\) 是 \(O(X^3)\) 的,再枚举 \(c_i\) 是调和级数的,多一个 \(\log X\),实际上有很多地方 dp 值是 \(0\) 且常数很小。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 505, mod = 1e9 + 7;
int n, a[maxn], c[maxn], x, dp[maxn][maxn][maxn], C[maxn][maxn], inv[maxn], jc[maxn], pw[maxn][maxn];
void prepare() {
C[0][0] = 1;
for (int i = 1; i <= x + 1; i++) {
C[i][0] = 1;
for (int j = 1; j <= x + 1; j++)
C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod;
}
inv[0] = inv[1] = jc[0] = 1;
for (int i = 1; i <= x + 1; i++)
jc[i] = jc[i - 1] * i % mod;
for (int i = 2; i <= x + 1; i++)
inv[i] = (mod - mod / i) * inv[mod % i] % mod;
for (int i = 2; i <= x + 1; i++)
inv[i] = inv[i - 1] * inv[i] % mod;
for (int i = 0; i <= x + 1; i++) {
pw[i][0] = 1;
for (int j = 1; j <= n; j++)
pw[i][j] = pw[i][j - 1] * i % mod;
}
}
signed main() {
cin >> n >> x;
prepare();
for (int l, i = 1; i <= n; i++)
cin >> l, c[l]++;
dp[x + 1][0][0] = 1;
//cout << 123 << endl;
for (int i = x; i >= 1; i--)
for (int j = 0; j <= x; j++)
for (int k = 0; k <= x; k++)
for (int l = 0; k >= l * i && j >= l && k >= j * (i - 1); l++)
dp[i][j][k] = (dp[i][j][k] + dp[i + 1][j - l][k - l * i] * inv[l] % mod * pw[(k - j * (i - 1))][c[i]]) % mod;
int ans = 0;
for (int i = 0; i <= x; i++)
for (int j = 0; j <= x; j++)
ans = (ans + dp[1][i][j] * jc[i] % mod * C[x + 1 - j][i] % mod * ((x - j) % 2 ? mod - 1 : 1) % mod) % mod;
cout << ans << endl;
return 0;
}

浙公网安备 33010602011771号