专栏文章
Not Too Many Balls-ABC332G
AT_abc332_g题解参与者 2已保存评论 3
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 3 条
- 当前快照
- 1 份
- 快照标识符
- @miobke43
- 此快照首次捕获于
- 2025/12/02 16:31 3 个月前
- 此快照最后确认于
- 2025/12/02 16:31 3 个月前
题目大意
给定 种球和 个盒子,对于第 种球有 个,第 个盒子的容量为 ,且对于所有满足 且 的整数对 ,第 个球盒子最多放 个第 种球,求最大的放置数。
。
Sol
不难想到网络流算法。
建立源汇点,对于每种球和每一个盒子都新建一个点,源点向球连边,流量为 ,盒子向汇点连边,流量为 ,球向盒子连边,流量为 ,答案即为最大流。
在此数据范围下,网络流复杂度会炸,由于这个图的结构特殊性,考虑用 模拟网络流。
先将最大流转为最小割,则我们所求即为:
我们设 ,则对于所有满足 的集合 求出最小的 ,显然背包解决即可,则原式化为:
对于每一个可能的 ,贪心地取 ,不难发现将 按照 排序,则取 和取 的部分为一段前缀和一段后缀,在枚举 的过程中同时维护两部分的分界点即可。
由于在递增枚举 的过程中,分界点也是单调递增的,最多移动 次,保证了复杂度的正确性。
时间复杂度 。
Code
CPP#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5e2 + 5, M = 5e5 + 5;
int a[N], b[M], dp[N * N], n, m, Ans = 1e18, pos[M];
bool compare(int i, int j){return (int)(b[i] / i) < (int)(b[j] / j);}
signed main(){
cin >> n >> m;
for(int i = 1; i <= n; i++)cin >> a[i];
for(int i = 1; i <= m; i++)cin >> b[i];
memset(dp, 0x3f, sizeof dp);
dp[0] = 0;
for(int i = 1; i <= n; i++)
for(int k = n * (n + 1) / 2; k >= i; k--)
dp[k] = min(dp[k], dp[k - i] + a[i]);//01背包
for(int i = 1; i <= m; i++)pos[i] = i;
sort(pos + 1, pos + m + 1, compare);//按照b[j] / j升序排序
int sum1 = m * (m + 1) / 2, sum2 = 0, loc = 1;
for(int i = 0; i <= n * (n + 1) / 2; i++){
while(i * pos[loc] > b[pos[loc]]){//维护分界点
sum1 -= pos[loc];
sum2 += b[pos[loc]];
loc++;
}
Ans = min(Ans, dp[n * (n + 1) / 2 - i] + i * sum1 + sum2);//维护答案
}
cout << Ans << endl;
return 0;
}
相关推荐
评论
共 3 条评论,欢迎与作者交流。
正在加载评论...