zoukankan      html  css  js  c++  java
  • [NOIP2015-普及组] 推销员

    • 前言

      未经允许,请勿转载。

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

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

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


    • 题目

      阿明是一名推销员,他奉命到螺丝街推销他们公司的产品。螺丝街是一条死胡同,出口与入口是同一个,街道的一侧是围墙,另一侧是住户。

      螺丝街一共有(N)家住户,第 (i) 家住户到入口的距离为 (S_i) 米。由于同一栋房子里可以有多家住户,所以可能有多家住户与入口的距离相等。阿明会从入口进入,依次向螺丝街的 (X) 家住户推销产品,然后再原路走出去。

      阿明每走 (1) 米就会积累 (1) 点疲劳值,向第 (i) 家住户推销产品会积累 (A_i) 点疲劳值。阿明是工作狂,他想知道,对于不同的 (X) ,在不走多余的路的前提下,他最多可以积累多少点疲劳值。


    • 分析

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

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

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

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

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

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

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

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

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

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

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


    • 举例子了。

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

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

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

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

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

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

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

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

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

      这样子预处理,就可以实现(O(nlogn))(qaq)

    • 代码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
    ",max(sum[i]+q[i],sum[i-1]+h[i]));
        return 0;
    }
    

    (by) Rainy7

  • 相关阅读:
    [哈工大操作系统]一、环境配置
    [算法笔记]带权并查集
    C++:Reference to non-static member function must be called
    [算法笔记]并查集
    C++:string.size()比较问题
    [算法笔记]二分总结
    【LeetCode每日一题】2020.10.15 116. 填充每个节点的下一个右侧节点指针
    1Manjaro的安装
    【《你不知道的JS(中卷②)》】一、 异步:现在与未来
    【LeetCode每日一题】2020.7.14 120. 三角形最小路径和
  • 原文地址:https://www.cnblogs.com/Rainy7/p/12275952.html
Copyright © 2011-2022 走看看