【差分 Trick】CF626F Group Projects

发布时间 2023-07-03 14:59:37作者: Custlo

模拟赛垫底哥来补题了。

先排序,考虑到原来的弱智状态难以描述,我们可以这样写:

\(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;
}