Description:
1<=n<=200,1<=k<=1000
题解:
首先肯定得排个序,再考虑如何dp。
一个组的贡献可以是最大值减最小值,也可以是相邻的两个数的差的和。
这样就可以dp了,对于一个组,如果它没有结尾,那么每往后移以下,贡献就会增加。
可以设fi,j,k表示当前做到第i个数,有j个组还没有结尾,贡献和已经是k的方案数。
对于新来的一个数,有4种情况:
1.新开一组但不做结尾。
2.新开一组且做结尾。
3.接到已有的一组后但是不做结尾。
4.接到已有的一组后并做结尾。
根据这4种情况可得方程。
Code:
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
#define fo(i, x, y) for(int i = x; i <= y; i ++)
using namespace std;
const int mo = 1e9 + 7;
const int N = 201, M = 1001;
int n, k, o, a[N], f[2][N][M];
int main() {
freopen("group.in", "r", stdin);
freopen("group.out", "w", stdout);
scanf("%d %d", &n, &k);
fo(i, 1, n) scanf("%d", &a[i]);
sort(a + 1, a + n + 1);
f[o][1][0] = f[o][0][0] = 1;
fo(i, 2, n) {
o = !o;
memset(f[o], 0, sizeof f[o]);
fo(j, 0, i - 1) {
fo(p, 0, k) {
int v = p + j * (a[i] - a[i - 1]);
if(v > k) break;
f[o][j + 1][v] += f[!o][j][p]; f[o][j + 1][v] %= mo;
f[o][j][v] += f[!o][j][p]; f[o][j][v] %= mo;
if(j) f[o][j][v] += (ll)f[!o][j][p] * j % mo, f[o][j][v] %= mo;
if(j) f[o][j - 1][v] += (ll)f[!o][j][p] * j % mo, f[o][j - 1][v] %= mo;
}
}
}
int ans = 0;
fo(p, 0, k) ans = (ans + f[o][0][p]) % mo;
printf("%d", ans);
}
本文介绍了一种使用动态规划解决特定数值分组问题的方法。针对给定的数值范围,通过排序和状态转移方程,有效地求解不同分组方式下的方案数。该问题的核心在于如何合理地分配数值到各个组中,并确保最终的分组结果满足题目要求的最大值与最小值之差或相邻数值差的和等条件。
284

被折叠的 条评论
为什么被折叠?



