• P2672 推销员 优先队列 + 贪心


    ~~~题面~~~

    题解:

    我会说我想这道普及组题都想了好久么。。。。

    不熟练的普及组选手.jpg

    最后随便猜了一个结论居然是对的。。。

    放结论:

    假设x = i的最优决策为f[i], 那么f[i + 1]一定包括f[i].

    也就是说f[i+1]一定可以由f[i]推出来。

    所以f[i]一定是由f[i+1]中选定的所有点中去掉一个得来的。

    即下一次选择一定是基于上一次选择的。。。

    至于证明嘛。。。感性理解吧。

    因为选哪户人家推销其实相互没太多联系。而且选i个推销肯定选满是最划得来的。。。。

    大概是这么理解的吧。(反向理解可能更加好理解一点)

    所以有了这个结论就很好解决了。

    因为f[n]的最优决策肯定是n个点全选。

    所以我们从这个已知的往前推。

    于是我们来观察这n个点,到底删掉哪个减掉的疲劳值最小呢?

    首先选中的这些点可以看做一个有序点集,位置由s[i]的大小所决定。

    因此我们记last[x]为在x前面的第一个点的id, Next[x]为在x后面的第一个点的id。

    于是有两种情况:

    1,删去的点在末尾。

      此时减掉的疲劳值为a[x] + 2 * (s[x] - s[last[x]])

    2,删去的点在中间。

      那么此时对走路的距离没有任何影响,因此我们只需要减a[x]即可。

    值得注意的是,当末尾点k为a[i]最小的点时, 我们需要再取出次小的点来做比较,因为a[k]虽然最小,但由于要走很多路,所以a[k] + 2 * (s[k] - s[last[k]])并不一定小于a[i](i < k, 且i ∈ 点集),因此我们需要进一步比较再做取舍。

    而k不是a[i]最小的点时,因为a[k]就已经大于a[i]了,所以减去的疲劳值肯定要大于a[i]了,因此直接删最小的点就可以了。

    这里的最小和次小由于要支持插入,删除,查询,因此我们使用优先队列来实现。

    为了方便查询元素的id,,,于是我又建了一个结构体、。

    代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define R register int
     4 #define LL long long
     5 #define getchar() *o++
     6 #define AC 100100
     7 char READ[5001000], *o = READ;
     8 int n;
     9 int s[AC], a[AC], ans[AC], Next[AC], last[AC], r;
    10 struct node{
    11     int w, id;
    12 };
    13 
    14 struct cmp{
    15     bool operator () (node a, node b)
    16     {
    17         return a.w > b.w;
    18     }
    19 };
    20 
    21 priority_queue <node, vector<node>, cmp> q;
    22 
    23 inline int read()
    24 {
    25     int x = 0; char c = getchar();
    26     while(c > '9' || c < '0') c = getchar();
    27     while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    28     return x;
    29 }
    30 
    31 void pre()
    32 {
    33     n = read();
    34     for(R i = 1; i <= n; i++) s[i] = read();
    35     for(R i = 1; i <= n; i++) 
    36     {
    37         a[i] = read(); 
    38         q.push((node){a[i], i});    
    39         ans[n] += a[i];    
    40         last[i] = i - 1;
    41         if(i != n) Next[i] = i + 1;
    42     }
    43     ans[n] += s[n] * 2, r = n;
    44 }
    45 
    46 void work()
    47 {
    48     int b = n - 1;node x, now;
    49     for(R i = b; i; i--)
    50     {
    51         x = q.top();
    52         if(x.id == r)
    53         {
    54             q.pop();
    55             now = q.top();
    56             if(now.w < x.w + (s[x.id] - s[last[x.id]]) * 2)
    57             {
    58                 q.pop();
    59                 Next[last[now.id]] = Next[now.id];
    60                 last[Next[now.id]] = last[now.id];
    61                 ans[i] = ans[i + 1] - now.w;
    62                 q.push(x);
    63             }
    64             else//不然就删后者
    65             {
    66                 Next[now.id] = 0;
    67                 ans[i] = ans[i + 1] - x.w - 2 * (s[x.id] - s[last[x.id]]);
    68                 r = last[x.id];//移动末项
    69             }
    70         }
    71         else//不然直接就删中间的了
    72         {
    73             q.pop();
    74             Next[last[x.id]] = Next[x.id];
    75             last[Next[x.id]] = last[x.id];
    76             ans[i] = ans[i + 1] - x.w;
    77         }
    78     }
    79     for(R i = 1; i <= n; i++) printf("%d
    ", ans[i]);
    80 }
    81 
    82 int main()
    83 {
    84     freopen("in.in", "r", stdin);
    85     fread(READ, 5000000, 1, stdin);
    86     pre();
    87     work();
    88     fclose(stdin);
    89     return 0;
    90 }
    View Code
  • 相关阅读:
    翻String.Format源码发现的新东西:StringBuilderCache
    禁止Asp.Net WebService 的Test页面功能
    利用XML序列化和Asp.Net Web缓存实现站点配置文件
    使用.NET配置文件appSettings元素的File属性
    <probing> 元素指定扩展Asp.Net加载程序集位置
    Windbg .net内存调试有用的命令(笔记 )
    The Dangers of the Large Object Heap(转载,LOH内存碎片情景重现)
    Advanced .NET Debugging: Managed Heap and Garbage Collection(转载,托管堆查内存碎片问题解决思路)
    调试.NET程序OutOfMemoryException (转载)
    mysql数据库之索引和分析索引
  • 原文地址:https://www.cnblogs.com/ww3113306/p/9315731.html
Copyright © 2020-2023  润新知