专栏文章
AT-AGC018-C 题解
AT_agc018_c题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @miqrd30g
- 此快照首次捕获于
- 2025/12/04 09:29 3 个月前
- 此快照最后确认于
- 2025/12/04 09:29 3 个月前
科技:
wqs 二分(板子)
思路:
首先, 很好做:
设二维背包 ,表示金币取 个,银币取 个,则有:
然后,我们不难证明 和 分别构成两个凸包:
考虑归纳。初始时,只有 ,其余可以视为负无穷,因此满足凸性。再观察转移式本质上就是将三个凸包平移后再取 ,显然做完这些操作后我们得到的还是凸包。
因此,我们可以先用 wqs 二分把问题从三维降至二维,变成只限制一种币取的个数。我们不妨限制银币恰好取 个,那么,每个人的贡献就变成了 或 ,并且要有恰好 个人选 。
这个问题简单贪心即可:我们可以把所有人按 排序,前 大的人选 ,后面的人都选 。
设二维背包 ,表示金币取 个,银币取 个,则有:
然后,我们不难证明 和 分别构成两个凸包:
考虑归纳。初始时,只有 ,其余可以视为负无穷,因此满足凸性。再观察转移式本质上就是将三个凸包平移后再取 ,显然做完这些操作后我们得到的还是凸包。
因此,我们可以先用 wqs 二分把问题从三维降至二维,变成只限制一种币取的个数。我们不妨限制银币恰好取 个,那么,每个人的贡献就变成了 或 ,并且要有恰好 个人选 。
这个问题简单贪心即可:我们可以把所有人按 排序,前 大的人选 ,后面的人都选 。
代码:
CPP#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const int N = 1e5 + 5;
int n,x,y,z,cnt,a[N],b[N],c[N];
struct Node{int w1,w2,t;} p[N];
bool cmp(Node x,Node y)
{
if(x.w2 - x.w1 != y.w2 - y.w1) return x.w2 - x.w1 > y.w2 - y.w1;
return x.t < y.t;
}
ll check(int k)
{
ll ret = 0;
cnt = 0;
for(int i = 1;i <= n;i++)
{
if(a[i] - k >= c[i]) p[i].w1 = a[i] - k,p[i].t = 1;
else p[i].w1 = c[i],p[i].t = 0;
p[i].w2 = b[i];
}
sort(p + 1,p + n + 1,cmp);
for(int i = 1;i <= y;i++) ret += p[i].w2;
for(int i = y + 1;i <= n;i++) ret += p[i].w1,cnt += p[i].t;
return ret;
}
int main()
{
scanf("%d%d%d",&x,&y,&z);
n = x + y + z;
for(int i = 1;i <= n;i++) scanf("%d%d%d",&a[i],&b[i],&c[i]);
int l = -1e9,r = 1e9,mid;
while(r - l > 1)
{
mid = ((l + r) >> 1);
check(mid);
if(cnt >= x) l = mid;
else r = mid;
}
printf("%lld\n",check(l) + 1LL * l * x);
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...