P9339 [JOISC 2023] 曲奇 题解
Description
莉婕喜欢做饼干。她制作了
-
对于每个盒子,其中的饼干种类应不同。
-
对于每个盒子,其中的饼干数量应等于以下
个数字之一: 。
编写一个程序,给出莉婕制作的饼干信息和将饼干装箱的条件,确定是否可能将所有饼干包装到盒子中。此外,如果可以将所有饼干包装在盒子中,则您的程序应输出最少的盒子数量。
Solution
假设有
首先
然后把
这个东西是必要条件,下面用 Hall 定理证明这个也是充分的。
首先建出二分图,左部点是盒子,右部点是饼干,
根据 Hall 定理,对于任意盒子的子集
然后就可以 dp 了。
设
用 bitset 转移是
时间复杂度:
Code
#include <bits/stdc++.h> // #define int int64_t const int kMaxN = 1.5e4 + 5; int n, m, mm, s; int a[kMaxN], b[kMaxN], c[kMaxN], lim[kMaxN], coef[kMaxN]; std::vector<std::bitset<kMaxN>> f[kMaxN]; std::bitset<kMaxN> g[kMaxN]; void getcc(int i, int j, int k) { // std::cerr << i << ' ' << j << ' ' << k << '\n'; if (i == m + 1) return assert(!j && !k); while (1) { if (j < f[i + 1].size() && f[i + 1][j][k]) return getcc(i + 1, j, k); c[++mm] = b[i], --j, k -= b[i]; } } void dickdreamer() { std::cin >> n; for (int i = 1; i <= n; ++i) { std::cin >> a[i]; ++coef[1], --coef[a[i] + 1], lim[a[i] + 1] += a[i]; s += a[i]; } std::cin >> m; for (int i = 1; i <= m; ++i) std::cin >> b[i]; for (int i = 1; i <= s; ++i) { lim[i] += lim[i - 1], coef[i] += coef[i - 1]; } for (int i = 0; i <= s; ++i) { lim[i] += i * coef[i]; g[i].reset(), g[i].flip(); g[i] ^= (g[i] << (lim[i] + 1)); // std::cerr << lim[i] << " \n"[i == s]; } f[m + 1].resize(1), f[m + 1][0].reset(), f[m + 1][0][0] = 1; for (int i = m; i; --i) { f[i].resize(s / b[i] + 1); for (int j = 0; j < f[i].size(); ++j) f[i][j].reset(); for (int j = 0; j < f[i + 1].size(); ++j) f[i][j] = f[i + 1][j]; for (int j = 0; j < f[i].size(); ++j) { f[i][j] &= g[j]; if (j + 1 < f[i].size()) f[i][j + 1] |= (f[i][j] << b[i]); } // std::cerr << "!!! " << b[i] << ' ' << f[i].size() << '\n'; } int cnt = -1; for (int i = 0; i < f[1].size(); ++i) { if (f[1][i][s]) { cnt = i; break; } } if (!~cnt) return void(std::cout << "-1\n"); getcc(1, cnt, s); std::cout << cnt << '\n'; std::priority_queue<std::pair<int, int>> q; for (int i = 1; i <= n; ++i) q.emplace(a[i], i); for (int i = 1; i <= cnt; ++i) { std::vector<int> vec; for (int j = 1; j <= c[i]; ++j) { vec.emplace_back(q.top().second); q.pop(); } std::cout << c[i] << ' '; for (auto x : vec) { std::cout << x << ' '; --a[x]; assert(a[x] >= 0); // q.emplace(a[x], x); if (a[x]) q.emplace(a[x], x); } std::cout << '\n'; } } int32_t main() { #ifdef ORZXKR freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0); int T = 1; // std::cin >> T; while (T--) dickdreamer(); // std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n"; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
2024-02-17 CF1365G Secure Password 题解