小题

洛谷P4653

一句话题意:给两个长为 ndouble 数组 a , b ,定义收益: a 数组中选 x 个数放前面, b 数组中选 y 个数放前面,收益为 min(i=1xai,i=1ybi)xy 。求最大收益。

做法: TJ 说用三分做,但我只会贪心。我们把 a,b 都从大到小排序,分别求前缀和。显然的是我们从大到小选一定是最优的。首先我们想枚举 i,j ,表示 ab 数组分别选到第几个,算答案。但是就 Θ(n2) 了。我们发现,如果我选的 sumai 刚好比 sumbj 小(或等),那么如果我再把 b 数组往后选一个,肯定是在做无用功。因此我们只需考虑两边和相当的情况,即对每个位置在另一个数组中找lower_bound。一个细节是,要用总和更小的数组去找另一个。(玄学)


其实最开始是这样想的:从大到小排好序后,直接用两个指针扫两边,贪心找和更小的一边。这样做和上述做法本质一样,但不知道为什么 pt2 一直 WA ......

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
const double eps = 1e-6;
int n;
double a[N], b[N], sma[N], smb[N];
double res;
int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) scanf("%lf%lf", &a[i], &b[i]);
    sort(a + 1, a + n + 1); sort(b + 1, b + n + 1);
    for(int i = n; i; --i)
    {
    	sma[n - i + 1] = sma[n - i] + a[i];
    	smb[n - i + 1] = smb[n - i] + b[i];
	}
	if(smb[n] < sma[n])
	{
		swap(a, b);
		swap(sma, smb);
	}
	int p;
	for(int i = 1; i <= n; ++i)
	{
		p = lower_bound(smb + 1, smb + n + 1, sma[i]) - smb;
		res = max(res, max(sma[i] - i - p, smb[p - 1] - i - p + 1));
	}
	printf("%.4lf", res);
	return 0;
}
//后一种WA点的做法
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n;
double a[N], b[N];
double res;
int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) scanf("%lf%lf", &a[i], &b[i]);
    sort(a + 1, a + n + 1); sort(b + 1, b + n + 1);
    int p1 = n, p2 = n;
    double x = 0, y = 0;
    while(p1 && p2)
    {
    	if(x <= y)
    		x += a[p1--];
    	else
			y += b[p2--];
		--x; --y;
		res = max(res, min(x, y));
	}
	printf("%.4lf", res);
	return 0;
}
posted @   Faker_yu  阅读(60)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示