E - Lucky bag
E - Lucky bag
Problem Statement
AtCoder Inc. sells merchandise on its online shop.
There are items remaining in the company. The weight of the -th item is .
Takahashi will sell these items as lucky bags.
He wants to minimize the variance of the total weights of the items in the lucky bags.
Here, the variance is defined as , where are the total weights of the items in the lucky bags, and is the average of .
Find the variance of the total weights of the items in the lucky bags when the items are divided to minimize this value.
It is acceptable to have empty lucky bags (in which case the total weight of the items in that bag is defined as ),
but each item must be in exactly one of the lucky bags.
Constraints
- All input values are integers.
Input
The input is given from Standard Input in the following format:
Output
Print the variance of the total weights of the items in the lucky bags when the items are divided to minimize this value.
Your output will be considered correct if the absolute or relative error from the true value is at most .
Sample Input 1
5 3
3 5 3 6 3
Sample Output 1
0.888888888888889
If you put the first and third items in the first lucky bag, the second and fifth items in the second lucky bag, and the fourth item in the third lucky bag, the total weight of the items in the bags are , , and , respectively.
Then, the average weight is ,
and the variance is , which is the minimum.
Note that multiple items may have the same weight, and that each item must be in one of the lucky bags.
解题思路
为了方便这里用 来表示题目中的 ,且物品和分组的下标都从 开始。
容易知道 ,因此 是一个常量。所以要使得式子 尽可能小,只需让 尽可能小。因此实际上要考虑的是每组应该放哪些物品才能使得式子尽可能小。
考虑动态规划,定义 表示已将状态 所表示的物品放入前 组的所有方案中 的最小值,其中 是一个 位的二进制数,如果第 位是 表示已选第 个物品。为了方便这里定义 表示状态 中已选物品的总价值,根据第 组含有哪些物品进行状态划分,因此有状态转移方程
其中 也是二进制状态,表示 关于 的子集。例如 ,那么其子集就是 ,,,。用 表示二进制数 中 的数量,那么 的子集数量就是 。遍历 的所有子集的方法和证明请参考链接。
整个 dp 的时间复杂度是 。其中 可由 的二项式定理推出。计算量上限大概是 级别,在 atcoder 上 左右就可以跑出结果。
最终答案就是 。
AC 代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 15, M = 1 << 15;
int w[N], s[M];
double f[N][M];
int main() {
int n, m;
scanf("%d %d", &n, &m);
for (int i = 0; i < n; i++) {
scanf("%d", w + i);
}
for (int i = 0; i < 1 << n; i++) {
for (int j = 0; j < n; j++) {
if (i >> j & 1) s[i] += w[j];
}
}
double avg = 1.0 * s[(1 << n) - 1] / m;
for (int i = 0; i < m; i++) {
for (int j = 0; j < 1 << n; j++) {
if (!i) {
f[i][j] = (s[j] - avg) * (s[j] - avg);
}
else {
f[i][j] = f[i - 1][j] + avg * avg;
for (int k = j; k; k = (k - 1) & j) {
f[i][j] = min(f[i][j], f[i - 1][j ^ k] + (s[k] - avg) * (s[k] - avg));
}
}
}
}
printf("%.10f", f[m - 1][(1 << n) - 1] / m);
return 0;
}
参考资料
Editorial - AtCoder Beginner Contest 332:https://atcoder.jp/contests/abc332/editorial/7929
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/17894691.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效