[CF626F] Group Projects

[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;
}
原文地址:https://www.cnblogs.com/mollnn/p/14658081.html