CodeForces 1886E I Wanna be the Team Leader
把题意抽象成,给你长为 的序列 和长为 的序列 ,初始有 个空集合(可重集), 中的每个元素至多被分到 个集合中的一个。要求最后第 个集合 不为空,且 。要求构造方案或报告无解。
先把 从大到小排序。发现最后每个集合分到的一定是在排序后序列的一段区间。因为 显然比 劣。
然后考虑一个从前往后分配集合元素的可行性 dp。设 为当前 中 的元素被分配完了, 为已经考虑完的集合的编号集合为 。转移枚举下一段的右端点 ,枚举 被分到第 个集合,有 。要求 。
发现这个 dp 太蠢了。考虑直接把第一维塞进 dp 值中。重新设 为已经考虑完的集合的编号集合为 ,若 被分配完了, 的最小值。预处理出 表示最小的 使得 ,转移考虑枚举下一个集合是第 个,有 。
求 可以双指针,因为 随 增大而不降。所以整个的复杂度就是 。
code
// Problem: E. I Wanna be the Team Leader // Contest: Codeforces - Educational Codeforces Round 156 (Rated for Div. 2) // URL: https://codeforces.com/contest/1886/problem/E // Memory Limit: 512 MB // Time Limit: 2000 ms // // Powered by CP Editor (https://cpeditor.org) #include <bits/stdc++.h> #define pb emplace_back #define fst first #define scd second #define mkp make_pair #define mems(a, x) memset((a), (x), sizeof(a)) using namespace std; typedef long long ll; typedef double db; typedef unsigned long long ull; typedef long double ldb; typedef pair<ll, ll> pii; const int maxn = 200100; const int maxm = (1 << 20) + 50; ll n, m, b[25], g[25][maxn], f[maxm], p[maxm]; vector<int> ans[25]; struct node { ll x, i; } a[maxn]; void solve() { scanf("%lld%lld", &n, &m); for (int i = 1; i <= n; ++i) { scanf("%lld", &a[i].x); a[i].i = i; } sort(a + 1, a + n + 1, [&](const node &a, const node &b) { return a.x > b.x; }); for (int i = 1; i <= m; ++i) { scanf("%lld", &b[i]); } for (int i = 1; i <= m; ++i) { for (int j = 1, k = 1; j <= n; ++j) { k = max(k, j); while (k <= n && a[k].x * (k - j + 1) < b[i]) { ++k; } g[i][j] = k; } } mems(f, 0x3f); f[0] = 0; for (int S = 0; S < (1 << m); ++S) { if (f[S] >= n) { continue; } for (int i = 1; i <= m; ++i) { if (S & (1 << (i - 1))) { continue; } int T = S | (1 << (i - 1)); if (f[T] > g[i][f[S] + 1]) { f[T] = g[i][f[S] + 1]; p[T] = i; } } } if (f[(1 << m) - 1] > n) { puts("NO"); return; } puts("YES"); int S = (1 << m) - 1; while (S) { int T = S ^ (1 << (p[S] - 1)); for (int i = f[T] + 1; i <= f[S]; ++i) { ans[p[S]].pb(a[i].i); } S = T; } for (int i = 1; i <= m; ++i) { printf("%d ", (int)ans[i].size()); for (int x : ans[i]) { printf("%d ", x); } putchar('\n'); } } int main() { int T = 1; // scanf("%d", &T); while (T--) { solve(); } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)