1 条题解

  • 0
    @ 2025-8-24 21:40:18

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Rainy7
    恍惚间,宝石与花朵都死去了。

    搬运于2025-08-24 21:40:18,当前版本为作者最后更新于2019-07-13 20:17:40,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    • 前言

      是介个样子,不知道是不是我太了,我看了好多题解,然后花了好多时间才明白贪心具体。

      于是我决定自己写一题解,会详细一些的。本题解会有 贪心思路+例子模拟贪心

      我觉得我挺有良心的,,希望大家都能看懂QAQ


    • 题目大意

      推销员阿明,要给住在某街的N个用户推销,走一米会增加1的疲劳值,第i家距离路口s[i]s[i]米(可能会有重复的s[i]s[i])给第i家推销会增加a[i]a[i]。全部推销完,还要原路返回。

      现在,依次向XX用户推销,对于不同的XX,阿明想知道最大疲劳值


    • 分析

      距离是真的烦人,那就不管他吧。因为想要疲劳值最大,那么先按照疲劳值从大到小排序一边

      此时,可以判断出,最大值可能为:对于每个XX,只要加上XX大的疲劳值,再加上这些数中距离最远的并乘以2,也就是:

      sum(a[k])(1kX)+s[j]2sum(a[k])(1≤k≤X)+s[j]*2

      其中,s[j]s[j]表示前K个距离最远的,sum()表示和。

      但是,推销员可以通过走远一点,虽然疲劳值比前面小,但是有可能把路程一算,反而更大。

      因此,可以把a[]a[],即疲劳值中,XX大中的最小值,即第XX大的那一家舍去,看看能不能通过走更远来换取更大的疲劳值总和。

      而从后面看,一定也会存在一个最大值,把这个最大值和前面X1X-1个疲劳值总和加起来,看看会不会比前面第一种的情况大。

      证明:只需舍去最小值来走更远,无需舍去更多数来走更远。

      其实这也不是一个证明..

      因为已经从大到小排序了,所以,如果舍去22个疲劳值,那么后面只会在加上两个更小的疲劳值,以及两个之间最大的距离并乘2,那么这样还不如只舍去一个。

      2个不行,那么2个以上更是不行了。


    • 举例子了。

      硬讲太累了,还是用一个例子吧。

      //自动排序QAQ
      s[i]:1,3,4,5,11
      a[i]:5,4,2,1,1
      

      X==1X==1,直接取,那么值为:1×2+5=71×2+5=7,如果舍去最小的往后跑,值为:11×2+1=2311×2+1=23,所以,最大值就为max(7,11)=11max(7,11)=11

      X==2X==2,直接取,值为:3×2+5+4=153×2+5+4=15,把其中最小值舍去,也就是44去掉,往后跑值为:11×2+1+5=2811×2+1+5=28,那么最大值为max(15,28)=28max(15,28)=28

      若把次小疲劳值,即55,也往后跑,那么值为11×2+1=2411×2+1=24,可以发现,距离并未因此改变,仍为1111,而位置移后,疲劳值只会减少,故只要移动最小疲劳值。

      那么,最后一个问题,酱紫复杂度是会炸掉的,soso

      sum[]sum[]记录疲劳前缀和,这样子加的时候方便。

      q[]q[]记录前i个距离最大值,这样子就不用找啦!

      h[]h[]记录往后跑时,应该选哪个,也就是后i个的最大值。

      这样子预处理,就可以实现O(n)O(n)QAQQAQ

    • 代码QAQ

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    int n,sum[100010],q[100010],h[100010];//n 疲劳前缀和 前i个最大值 后i个最大值 
    struct node{
        int s;//距离
        int a;//疲劳 
    }v[100010];
    bool cmp(node x,node y){return x.a>y.a;}
    int main()
    {	scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&v[i].s); 
        for(int i=1;i<=n;i++)scanf("%d",&v[i].a);
        sort(v+1,v+1+n,cmp);//按疲劳排序 
        for(int i=1;i<=n;i++)sum[i]=sum[i-1]+v[i].a; 
        for(int i=1;i<=n;i++)q[i]=max(q[i-1],2*v[i].s);//前i个最大值
        for(int i=n;i>=1;i--)h[i]=max(h[i+1],2*v[i].s+v[i].a);//后i个最大值
        for(int i=1;i<=n;i++)printf("%d\n",max(sum[i]+q[i],sum[i-1]+h[i]));
        return 0;
    }
    

    byby 路人七

    • 1

    信息

    ID
    1719
    时间
    1000ms
    内存
    128MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者