zoukankan      html  css  js  c++  java
  • 洛谷 P2672 推销员

    嗯...

     

    题目链接:https://www.luogu.org/problem/P2672

     

    这个题是一个贪心的思想...

    我们会发现本题有一个特性,就是如果我们走到一个更远的地方,那么近的地方距离原点的距离我们可以忽略.

    最后疲劳值是由两部分组成的:路径疲劳值和推销疲劳值.又因为第一行提到的,所以我们可以选一个点k(后面解释),将每个状态下分为两种点:

    1.在当前k点的左面,这些点的疲劳值其实只有推销疲劳值,因为我们已经走得更远了,所以顺道处理这些就行,不需要走多余的路

    2.比当前k点的右面,这些点的疲劳值其实就是推销疲劳值+两倍路径疲劳值-两倍k的路径疲劳值

    而其实最大疲劳值就是这两种点各自的最大值的最大值,所以我们可以用两个大根堆来存,取两个堆顶的较大值即可.

    返回来,k是什么呢?k就是我们当前已经选过的点里最靠右的

    为什么呢?因为对我们来说只要某个点走了,则这个点左边所有点我们都可以顺路经过,并不需要多余路径疲劳值,所以我们只要记录最右即可.

    代码处理的一些细节:

    1.一开始右边的堆将所有点放进去,左边堆为空,选一个最大点为第一个k

    2.每当更新一个k,再将k左边所有的点推进左边堆

    3.那么我们更新k后怎么判断右边堆那些在当前k的左边呢?因为k是动态的,所以原来在右边的可能到右边我们只要判断当前元素和k谁到原点近即可,

    所以我们要不单要记录疲劳值,还要记录路径值,所以我们要定义结构体来构造堆

    //思路来自PD大佬lpy:https://www.cnblogs.com/lipeiyi520/p/11037364.html

    外加自己的优化(优化掉了很多东西

    AC代码:

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<algorithm>
     4 #include<queue> 
     5 
     6 using namespace std;
     7 
     8 const int maxn = 100005;
     9 
    10 struct node{
    11     int w, id, ans;
    12     node() { }
    13     bool operator < (const node & p) const{
    14         return w + 2 * id < p.w + 2 * p.id;
    15     }//重载运算符 
    16 } e[maxn];
    17 
    18 
    19 priority_queue <int> a;//左边点 
    20 priority_queue <node> b;//右边点 
    21 
    22 int m, cnt, n, k, j;
    23 
    24 inline void fir(){
    25     m = b.top().ans;//第一个值为最大值 
    26     printf("%d
    ", m);
    27     cnt = n - 1;//cnt用来记录当前i 
    28     k = b.top().id;//k转移到最大值的id 
    29     b.pop();
    30     for(j = 1; j <= n; j++){
    31         if(e[j].id >= k) break;//右边点 
    32         else a.push(e[j].w);//左边点 
    33     }//更新 
    34 }//第一次 
    35 
    36 inline void solve(){
    37     while(cnt--){
    38         if(b.top().ans - 2 * k >= a.top()){
    39             if(b.top().id <= k){//更新,若原右边点现在在左边 
    40                 b.pop();
    41                 cnt++;
    42                 continue;
    43             }//右边堆顶比左边堆顶大 
    44             m += b.top().ans - k * 2;//加最大值 
    45             k = b.top().id;//k转移 
    46             b.pop();
    47             while(j++ <= n){
    48                 if(e[j].id >= k) break;
    49                 else{
    50                     a.push(e[j].w);
    51                     b.pop();
    52                 }//右边转移到左边 
    53             }
    54         }
    55         else{
    56             m += a.top();
    57             a.pop();
    58         }//左边堆顶大 
    59         printf("%d
    ", m);
    60     }
    61 }
    62                 
    63 
    64 int main(){
    65     scanf("%d", &n);
    66     for(int i = 1; i <= n; i++) scanf("%d", &e[i].id);
    67     for(int i = 1; i <= n; i++){
    68         scanf("%d", &e[i].w);
    69         e[i].ans = e[i].w + 2 * e[i].id;
    70         b.push(e[i]);
    71     }
    72     fir();
    73     solve();
    74     return 0;
    75 }
    AC代码
  • 相关阅读:
    java面试题
    linux下的文件目录结构
    Linux的基础命令
    Linux系统的介绍
    逻辑思维题
    37-字符的全排列
    36-螺旋矩阵
    35-面试:如何找出字符串的字典序全排列的第N种
    34-数细线
    33-求极差
  • 原文地址:https://www.cnblogs.com/New-ljx/p/11246199.html
Copyright © 2011-2022 走看看