zoukankan      html  css  js  c++  java
  • 【贪心 堆】luoguP2672 推销员

    堆维护,贪心做法

    题目描述

    阿明是一名推销员,他奉命到螺丝街推销他们公司的产品。螺丝街是一条死胡同,出口与入口是同一个,街道的一侧是围墙,另一侧是住户。螺丝街一共有N家住户,第i家住户到入口的距离为Si米。由于同一栋房子里可以有多家住户,所以可能有多家住户与入口的距离相等。阿明会从入口进入,依次向螺丝街的X家住户推销产品,然后再原路走出去。

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

    输入输出格式

    输入格式:

    第一行有一个正整数N,表示螺丝街住户的数量。

    接下来的一行有N个正整数,其中第i个整数Si表示第i家住户到入口的距离。数据保证S1≤S2≤…≤Sn<10^8。

    接下来的一行有N个正整数,其中第i个整数Ai表示向第i户住户推销产品会积累的疲劳值。数据保证Ai<10^3。

    输出格式:

    输出N行,每行一个正整数,第i行整数表示当X=i时,阿明最多积累的疲劳值。


     这题在2016年做过,不过全WA了hhh……

    好吧今天提交4次前两次也是全WA……

    最初的思路

    假设现在右端点为i-1,有i优于j(i < j)那么有wi+2(s[i]-s[i-1])>wj+2(s[j]-s[i-1])即wi+2si>wj+2sj

    定义距离s[],疲劳值w[],f[i]表示在i..n中(2si+wi)最大值的编号。那么我们每次处理1..now-1的w[]最大值和value(f[i+1])两者最大值。重复这一过程。

    然而这个做法在调试时候就叉掉了……


    第一次WA

    非常NAIVE地把左右两边用了一个堆维护value()最小值,pretest过了就交了……

    但是这个value()与max_right_border有关系,所以这个堆是个假堆……

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int N = 1e5;
     4 int n,s[N],w[N],f[N],now,sum,rx;
     5 bool vis[N];
     6 int reval(int a)
     7 {
     8     if (a >= rx)return w[a]+2*(s[a]-s[rx]);
     9     return w[a];
    10 }
    11 struct cmp
    12 {
    13     bool operator () (int &a, int &b) const
    14     {
    15         return reval(a) < reval(b);
    16     }
    17 };
    18 priority_queue<int, vector<int>, cmp> p,q;
    19 int deal(int x)
    20 {
    21     if (x <= 0)return 0;
    22     while ((!q.empty())&&vis[q.top()])q.pop();
    23     if (q.empty())return 0;
    24     return q.top();
    25 }
    26 int dear(int x)
    27 {
    28     while ((!p.empty())&&(vis[p.top()]))p.pop();
    29     if (p.empty())return 0;
    30     return p.top();
    31 }
    32 int main()
    33 {
    34     scanf("%d",&n);
    35     for (int i=1; i<=n; i++)scanf("%d",&s[i]);
    36     for (int i=1; i<=n; i++){scanf("%d",&w[i]);p.push(i);}
    37     f[n] = n;
    38     for (int i=n-1; i>=1; i--)
    39         if (2*s[i]+w[i] > 2*s[f[i+1]]+w[f[i+1]])
    40             f[i] = i;
    41         else f[i] = f[i+1];
    42     now = 0;rx = 0;
    43     for (int i=1; i<=n; i++)
    44     {
    45         int dl = deal(now-1);
    46         int dr = dear(now+1);
    47         if (reval(dl) > reval(dr)){
    48             now = dl;
    49             vis[dl] = 1;
    50             sum += reval(dl);
    51         }else{
    52             sum += reval(dr);
    53             if (rx < dr){
    54                 for (int j=now+1; j<=dr; j++) q.push(j);
    55                 rx = dr;
    56             }
    57             now = dr;
    58             vis[dr] = 1;
    59         }
    60         printf("%d
    ",sum);
    61     }
    62     return 0;
    63 }
    View Code

    第二次WA

    观察变量调试重写了三十分钟,(此时并没有意识到假堆的严重性),看着调试输出还以为堆不假了(flag)。

    在查询时候,又多放了一个堆来解决:查询左边时候q.top()却在now右边的情况(反之亦然)。这pretest设计得真好

    按道理这样应该比第一次WA要慢一些,结果却快了200ms+...

    反正都是全WA

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int N = 1e5;
     4 int n,s[N],w[N],f[N],now,sum,rx;
     5 bool vis[N];
     6 int reval(int a)
     7 {
     8     if (a >= rx)return w[a]+2*(s[a]-s[rx]);
     9     return w[a];
    10 }
    11 struct cmp
    12 {
    13     bool operator () (int &a, int &b) const
    14     {
    15         return reval(a) < reval(b);
    16     }
    17 };
    18 priority_queue<int, vector<int>, cmp> p,q;
    19 int deal(int x)
    20 {
    21     if (x <= 0)return 0;
    22     queue<int>tt;
    23     while ((!q.empty())&&(q.top()>now||vis[q.top()]))
    24     {
    25         while ((!q.empty())&&(vis[q.top()]))q.pop();
    26         while ((!q.empty())&&(q.top()>now)){tt.push(q.top());q.pop();}
    27     }
    28     if (q.empty())return 0;
    29     int xx = q.top();
    30     while (!tt.empty()){q.push(tt.front());tt.pop();}
    31     return xx;
    32 }
    33 int dear(int x)
    34 {
    35     queue<int>tt;
    36     if (rx == n)return 0;
    37     if(rx!=n)while ((!p.empty())&&(p.top()<now||vis[p.top()]))
    38     {
    39         while ((!p.empty())&&(vis[p.top()]))p.pop();
    40 //        printf("ptop:%d
    ",p.top());
    41         while((!p.empty())&&(p.top()<now)){tt.push(p.top());p.pop();}
    42     }
    43     if (p.empty())return 0;
    44     int xx = p.top();
    45     while (!tt.empty()){p.push(tt.front());tt.pop();}
    46     return xx;
    47 }
    48 int main()
    49 {
    50     scanf("%d",&n);
    51     for (int i=1; i<=n; i++)scanf("%d",&s[i]);
    52     for (int i=1; i<=n; i++){scanf("%d",&w[i]);p.push(i);}
    53     f[n] = n;
    54     for (int i=n-1; i>=1; i--)
    55         if (2*s[i]+w[i] > 2*s[f[i+1]]+w[f[i+1]])
    56             f[i] = i;
    57         else f[i] = f[i+1];
    58     now = 0;rx = 0;
    59 //    for (int i=1; i<=n; i++)printf("%d ",f[i]);printf("#
    ");
    60     for (int i=1; i<=n; i++)
    61     {
    62         int dl = deal(now-1);
    63         int dr = dear(now+1);
    64 //        printf("now:%d rx:%d dl:%d %d-dr:%d %d
    ",now,rx,dl,reval(dl),dr,reval(dr));
    65         if (reval(dl) >= reval(dr)){
    66             now = dl;
    67             vis[dl] = 1;
    68             sum += reval(dl);
    69         }else{
    70             sum += reval(dr);
    71             if (rx < dr){
    72                 for (int j=rx+1; j<=dr; j++) q.push(j);
    73                 rx = dr;
    74             }
    75             now = dr;
    76             vis[dr] = 1;
    77         }
    78 //        for (int i=1; i<=n; i++)printf("%d ",vis[i]);puts("@");
    79         printf("%d
    ",sum);
    80     }
    81         int dl = deal(now-1);
    82         int dr = dear(now+1);
    83 //        printf("now:%d rx:%d dl:%d %d-dr:%d %d
    ",now,rx,dl,reval(dl),dr,reval(dr));
    84     return 0;
    85 }
    View Code

    第一次TLE

    好气啊打了一发纯粹的暴力(天哪有60分)

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int N = 1e5+35;
     4 int n,s[N],w[N],rx,now,sum;
     5 int a,b;
     6 bool vis[N];
     7 int reval(int x)
     8 {
     9     if (x < rx)return w[x];
    10     return w[x] + 2*(s[x]-s[rx]);
    11 }
    12 int main()
    13 {
    14     scanf("%d",&n);
    15     for (int i=1; i<=n; i++)scanf("%d",&s[i]);
    16     for (int i=1; i<=n; i++)scanf("%d",&w[i]);
    17     for (int k=1; k<=n; k++)
    18     {
    19         a = 0, b = 0;
    20         int cmp = 0, lb;
    21         for (int i=1; i<now; i++)
    22             if ((!vis[i])&&(a < w[i]))a = w[b = i];
    23         cmp = a;lb = b;
    24         a = 0,b = 0;
    25         for (int i=now+1; i<=n; i++)
    26             if ((!vis[i])&&(a < reval(i)))
    27                 a = reval(i),b = i;
    28         if (a > cmp){cmp = a;lb = b;}
    29         rx = max(rx, lb);
    30         vis[lb] = 1;
    31         now = lb;
    32         sum += cmp;
    33         printf("%d
    ",sum);
    34     }
    35     return 0;
    36 }
    View Code

    正解AC

    在打完暴力之后豁然开朗(???)意识到右部分大于max_right_border的枚举即可,这样一来左边的就变为小于max_right_border的部分,由此无所谓在now左部分的元素变动情况,从而可以保证堆的正确性。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int N = 1e5+35;
     4 int n,s[N],w[N],rx,now,sum;
     5 int a,b;
     6 bool vis[N];
     7 struct cmp
     8 {
     9     bool operator() (int &a, int &b)
    10     {
    11         return w[a] < w[b];
    12     }
    13 };
    14 priority_queue<int, vector<int>, cmp>q;
    15 void find()
    16 {
    17     while ((!q.empty())&&(vis[q.top()]))q.pop();
    18     if (q.empty())return;
    19     b = q.top();a = w[b];
    20 }
    21 int main()
    22 {
    23     scanf("%d",&n);
    24     for (int i=1; i<=n; i++)scanf("%d",&s[i]);
    25     for (int i=1; i<=n; i++)scanf("%d",&w[i]);
    26     for (int k=1; k<=n; k++)
    27     {
    28         a = 0, b = 0;
    29         int cmp = 0, lb;
    30         find();
    31         cmp = a;lb = b;
    32         a = 0,b = 0;
    33         for (int i=rx+1; i<=n; i++)
    34             if ((!vis[i])&&(a < w[i] + 2*(s[i]-s[rx])))
    35                 a = w[i] + 2*(s[i]-s[rx]),b = i;
    36         if (a > cmp)
    37         {
    38             cmp = a;
    39             lb = b;
    40         }
    41         if (rx < lb)
    42         {    
    43             for (int i=rx+1; i<=lb; i++)q.push(i);
    44             rx = lb;
    45         }
    46         vis[lb] = 1;
    47         now = lb;
    48         sum += cmp;
    49         printf("%d
    ",sum);
    50     }
    51     return 0;
    52 }
  • 相关阅读:
    url 百分号解密
    16.UA池和代理池
    15.scrapy框架之日志等级、请求传参、提高scrapy框架的爬取效率
    14. scrip框架之5大核心组件和post请求
    13.scrapy 框架之递归解析(手动发送请求),
    12. scrapy 框架持续化存储
    11.scrapy框架简介和基础应用
    10. 移动端数据爬取
    09.python之网络爬虫之selenium、phantomJs和谷歌无头浏览器的自动化操作
    08 python之网络爬虫之乱码问题
  • 原文地址:https://www.cnblogs.com/antiquality/p/8530645.html
Copyright © 2011-2022 走看看