Codeforces 626F Group Projects (DP)
题目链接 F.Group Projects
题意 把 个物品分成若干组,每个组的代价为组内价值的极差,求所有组的代价之和不超过 的方案数。
考虑 DP, 表示考虑到第 个物品的时候,还有 组尚未分配完毕,当前状态总代价为 的方案数
先把 升序排列,那么极差就可以转化为后面元素减前面的元素不听叠加的效果。
当考虑第 个物品的时候有 种转移方法 :
- 当前物品新开一组并且等待分配
- 当前物品新开一组并且这个物品单独当做一组
- 当前物品插入到之前的 组中的一组,并让这个组继续等待分配,那么有 种插入的方案
- 当前物品插入到之前的 组中的一组,并作为这个组的最大值(停止分配),同样有 种插入的方案
时间复杂度
view code
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define rep(i, a, b) for(int i(a); i <= b; ++ i)
#define dec(i, a, b) for(int i(a); i >= b; -- i)
//mt19937 mrand(random_device{}());
//int rnd(int x) { return mrand() % x;}
template <typename T> void chkmax(T &x, T y) { x = x >= y ? x : y; }
template <typename T> void chkmin(T &x, T y) { x = x <= y ? x : y; }
template <typename T> T abs(T x) {return x >= 0 ? x : -x;}
const int N = 202, M = 1010, MOD = 1e9 + 7;
int n, m;
int a[N];
LL f[2][N][M];
LL ans;
void add(LL &x, LL y) {
x += y;
while(x >= MOD) {
x -= MOD;
}
}
int main() {
scanf("%d%d", &n, &m);
rep(i, 1, n) {
scanf("%d", a + i);
}
std::sort(a + 1, a + 1 + n);
f[0][0][0] = 1;
//f[i][j][k] 表示 在前 i 个物品中选, 且剩余 j 个背包没有填完 并且 不平衡值 为 k
rep(i, 0, n - 1) {
std::memset(f[i + 1 & 1], 0, sizeof f[i + 1 & 1]);
rep(j, 0, n) {
rep(k, 0, m) { if(f[i & 1][j][k] && k + j * (a[i + 1] - a[i]) <= m) {
int cnt = k + j * (a[i + 1] - a[i]);
add(f[i + 1 & 1][j + 1][cnt], f[i & 1][j][k]); //新开一个背包 并且这个背包没有填完
add(f[i + 1 & 1][j][cnt], f[i & 1][j][k]); //新开一个背包 并且这个背包填完了
//放入之前的背包
if(j) {
add(f[i + 1 & 1][j][cnt], f[i & 1][j][k] * j % MOD); //没有填完任何一个背包
add(f[i + 1 & 1][j - 1][cnt], f[i & 1][j][k] * j % MOD); //填完一个背包
}
}
}
}
}
rep(i, 0, m) add(ans, f[n & 1][0][i]);
printf("%lld", ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】