洛谷-题解 P2672 【推销员】

独门思路!链表加优先队列!

这题一望,贪心是跑不掉了,但是我贪心并不好,所以想到了一个复杂一些但思路更保稳的做法

思路:

1 因为是离线操作,所以我们可以倒着求,先求x=n的情况,因为那样直接就知道了

2 用优先队列维护每个住户对疲劳度的贡献,维护最小的,因为x=i的疲劳度减去此时减去对疲劳度贡献最小的用户当然为x=i-1的疲劳度的最大值

3 需要用链表,因为当某个用户自己本身距离最远或比自己距离远且相邻的用户距离最远,那么删去这个用户,其他两个用户对疲劳度贡献分别更新(往返距离变化了)

4 一些小的细节,保证正确,因为优先队列里会有一些无用的用户

下面是可以简化和优化的代码,供参考思路

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<queue>
 7 #include<map>
 8 using namespace std;
 9 #define re register int
10 inline int read(){
11     int x=0,ff=1;char c=getchar();
12     while(c<'0'||c>'9'){if(c=='-')ff=-1;c=getchar();}
13     while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
14     return x*ff;
15 }
16 struct book{
17     int x,i,b;
18     bool friend operator <(book xx,book yy){
19         return xx.x>yy.x;
20     }
21    //重载运算
22 };
23 priority_queue<book>dl;
24 int a[100005],c[100005],tot[100005];
25 //a和c是距离和疲劳度,tot记录答案
26 int lb[100005],to[100005],s,tt[100005];
27 //lb是前驱,rb是后驱(链表)tt表示此时对i用户距离修改次数,与book中的b对应
28 bool v[100005],tl[100005];
29 //v表示次用户是否删过(其实可以省略)tl表示此点是否为最远距离
30 int main(){
31     int n=read(),t;t=n;
32     for(int i=1;i<=n;i++){
33         a[i]=read();
34     }
35     for(int i=1;i<n;i++){
36         c[i]=read();lb[i]=i-1;to[i]=i+1;
37         dl.push((book){c[i],i,0});s+=c[i];
38       //入队,并求出x=n的疲劳度,维护链表
39     }
40     c[n]=read();lb[n]=n-1;s+=c[n]+a[n]*2;
41     dl.push((book){c[n]+(a[n]-a[n-1])*2,n,1});
42     //初始化,与下面入队思路类似
43     tt[n]=1;tl[n]=1;
44     while(t){
45         if(dl.empty())break;
46         tot[t]=s;
47         book y=dl.top();dl.pop();
48         if(y.b<tt[y.i])continue;
49      //判断此用户是否为最新状态
50         if(v[y.i])continue;
51         v[y.i]=1;
52      //是否已删去
53         t--;
54         to[lb[y.i]]=to[y.i];
55         lb[to[y.i]]=lb[y.i];
56      //更新链表
57         s-=y.x;//更新疲劳度
58      //下面是关于前驱和后继的两种特殊情况
59         if(y.b){
60             if(lb[y.i]==0)break;tt[lb[y.i]]++;
61             dl.push((book){c[lb[y.i]]+2*(a[lb[y.i]]-a[lb[lb[y.i]]]),lb[y.i],tt[lb[y.i]]});
62         //特殊入队,表示此用户成为最远的,要更新删去此点的代价,注意,是往返
63         //其他入队于此类似
64         }
65         if(tl[to[y.i]]){
66             tt[to[y.i]]++;
67             dl.push((book){c[to[y.i]]+2*(a[to[y.i]]-a[lb[y.i]]),to[y.i],tt[to[y.i]]});
68         }
69     }
70     for(int i=1;i<=n;i++){
71         printf("%d\n",tot[i]);
72       //输出,此程序是离线做的
73     }
74     return 0;
75 }

洛谷上第39篇题解,这样管理员都给过可见我思路有多神奇

洛谷博客求赞

猜你喜欢

转载自www.cnblogs.com/ffrxy01bt/p/11099707.html
今日推荐