[CF626F] Group Projects - dp,差分
Description
有 (n) 个学生,每个学生有一个能力值 (a_i)。现在要把这些学生分成一些(任意数量的)组,每一组的“不和谐度”是该组能力值最大的学生与能力值最小的学生的能力值的差。求所有不和谐度之和不超过 (k) 的分组方案总数。
Solution
排序差分,其实就是去选若干个区间,那么每个区间有开始和结束,我们设 (f_{i,j,k}) 表示当前扫描到第 (i) 个人,当前未闭合的区间有 (j) 个,当前已经产生的代价是 (k) 的方案数,那么决策有四种:加入一个旧区间,开一个新区间并立刻结束,开一个新区间并延续下去,加入并关闭一个旧区间
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define now f[(i + 1) & 1]
#define last f[i & 1]
const int mod = 1e9 + 7;
int f[2][205][1005], n, K, a[205];
signed main()
{
ios::sync_with_stdio(false);
cin >> n >> K;
for (int i = 1; i <= n; i++)
cin >> a[i];
sort(a + 1, a + n + 1);
f[0][0][0] = 1;
for (int i = 0; i < n; i++)
{
memset(now, 0, sizeof now);
for (int j = 0; j <= i; j++)
{
for (int k = 0; k <= K; k++)
{
last[j][k] %= mod;
int t = k + j * (a[i + 1] - a[i]);
if (t > K)
continue;
now[j][t] += last[j][k] * j % mod;
now[j][t] += last[j][k];
if (j)
now[j - 1][t] += last[j][k] * j % mod;
now[j + 1][t] += last[j][k];
now[j][t] %= mod;
if (j)
now[j - 1][t] %= mod;
now[j + 1][t] %= mod;
}
}
}
int ans = 0;
for (int i = 0; i <= K; i++)
ans += f[n & 1][0][i], ans %= mod;
cout << ans << endl;
}