模拟赛垫底哥来补题了。
先排序,考虑到原来的弱智状态难以描述,我们可以这样写:
\(f_{i, j, k}\) 表示前 \(i\) 个,\(j\) 段未闭合,目前的不协调值为 \(k\)。
然后喜提 \(n^2 \sum a_i\) 的时间复杂的。
然后就是经典 trick time,这个可以看作很多线段。然后 \(a_r - a_l = \sum a_{i + 1} - a_i\) 这样很多段加起来。
所以我们可以用一个差分值直接维护多段的 \(a_max - a_min\)。考虑差分非负,那么这个 \(k\) 就非负,所以完全可以将其限制在 \(lim\) 这个范围内。
主打的就是一个啥都忘了,建议复习 ants man。
#include <bits/stdc++.h>
#define rep(i, l, r) for (int i = l; i <= r; i ++)
#define per(i, r, l) for (int i = r; i >= l; i --)
#define lc u << 1
#define rc u << 1 | 1
using namespace std;
const int _ = 200 + 5, __ = 1e3 + 5, mod = 1e9 + 7;
int n, lim;
int a[_], f[_][_][__];
long long ans;
int main () {
// freopen(".in", "r", stdin);
// freopen(".out", "w", stdout);
ios :: sync_with_stdio(0);
cin >> n >> lim;
rep(i, 1, n) cin >> a[i];
sort(a + 1, a + 1 + n);
f[0][0][0] = 1;
rep(i, 0, n - 1) {
rep(j, 0, n) {
int d = (a[i + 1] - a[i]) * j;
rep(k, 0, lim - d) {
(f[i + 1][j][k + d] += f[i][j][k] * 1ll * (j + 1) % mod) %= mod;
if (j != 0) (f[i + 1][j - 1][k + d] += f[i][j][k] * 1ll * j % mod) %= mod;
if (j != n) (f[i + 1][j + 1][k + d] += f[i][j][k]) %= mod;
}
}
}
rep(k, 0, lim) (ans += f[n][0][k]) %= mod;
cout << ans;
return 0;
}
标签:Group,非负,lim,rep,差分,Trick,CF626F,mod
From: https://www.cnblogs.com/Custlo/p/17522913.html