题意:胡同推销,走到第i家花费a[i]体力,推销额外花费b[i]体力,对于X【1~n】,找出推销X家的最大体力花费。
题解:由于距离门口的距离是一次性的,因此先对影响可能更灵活的推销花费b[i]从大到小排序,【因为b已排序】不妨试想最大花费为X个最大的b+ 前X个中最大的a×2,但我们发现,如果这X个数后面存在一个a,使得虽然b小了,但是这个a比前X个数中最大的a更大,并且选择这个a和其对应b的花费2×a+b后使得总花费比选择前X个数的花费要大,这样反而比我们的猜想更大。 因此,由于前X个之后的最大a【也就是最远距离】只能选一个,我们可以贪心地舍去前X大中含最小b的一组a、b,看看换成新的X之后满足上述条件的a、b,是否是比原来的总花费要大,如果大,换;如果不大,不换即可。 但我们又想,为什么只舍去一组最小b那一组值呢?舍2组、3组…会怎样? 答:其实是没必要的。舍去一组正好可以与X之后最大a的那一组"互换",如果换两组由于X后最大a只能选一组,但b却越往后越小【相当于第一小的与X后最大a那一组"互换",而第二小的b换了一个更小的b】,得不偿失。
代码如下:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5+10;
int n;
struct node
{
int a,b;
}s[N];
bool cmp(node x,node y)
{
return x.b>y.b;
}
int maxla[N],maxr[N],sumb[N];
//maxla[i]:第i个元素左边最大的a
//maxr[i]:第i个元素右边最大的一组2*a+b【前X组后待换的一定含最大的a】
//sumb[i]:前i个b的前缀和,便于计算
int main()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>s[i].a;
for(int i=1;i<=n;i++) cin>>s[i].b;
sort(s+1,s+1+n,cmp);
for(int i=1;i<=n;i++)
{
sumb[i]=sumb[i-1]+s[i].b;
maxla[i]=max(maxla[i-1],s[i].a);
}
for(int i=n;i>=1;i--) maxr[i]=max(s[i].a*2+s[i].b,maxr[i+1]);
for(int i=1;i<=n;i++)
{
cout<<max(maxla[i]*2+sumb[i],sumb[i-1]+maxr[i+1])<<endl;
//根据选不选后面定最大花费
}
return 0;
}
博客介绍了洛谷P2672题目,涉及NOIP2015竞赛中的一项胡同推销问题。通过贪心策略解决,首先对推销花费b[i]降序排序,然后尝试用前X个最大的b[i]加上2倍的对应a[i]作为初始最大花费。接着检查是否有更远的a[i]能带来更大的总花费。通过不断调整,找到最佳的推销组合,确保总花费最大化。C++代码提供了具体实现细节。
406

被折叠的 条评论
为什么被折叠?



