堆维护,贪心做法

题目描述

阿明是一名推销员,他奉命到螺丝街推销他们公司的产品。螺丝街是一条死胡同,出口与入口是同一个,街道的一侧是围墙,另一侧是住户。螺丝街一共有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有关系,所以这个堆是个假堆……

 #include<bits/stdc++.h>
using namespace std;
const int N = 1e5;
int n,s[N],w[N],f[N],now,sum,rx;
bool vis[N];
int reval(int a)
{
if (a >= rx)return w[a]+*(s[a]-s[rx]);
return w[a];
}
struct cmp
{
bool operator () (int &a, int &b) const
{
return reval(a) < reval(b);
}
};
priority_queue<int, vector<int>, cmp> p,q;
int deal(int x)
{
if (x <= )return ;
while ((!q.empty())&&vis[q.top()])q.pop();
if (q.empty())return ;
return q.top();
}
int dear(int x)
{
while ((!p.empty())&&(vis[p.top()]))p.pop();
if (p.empty())return ;
return p.top();
}
int main()
{
scanf("%d",&n);
for (int i=; i<=n; i++)scanf("%d",&s[i]);
for (int i=; i<=n; i++){scanf("%d",&w[i]);p.push(i);}
f[n] = n;
for (int i=n-; i>=; i--)
if (*s[i]+w[i] > *s[f[i+]]+w[f[i+]])
f[i] = i;
else f[i] = f[i+];
now = ;rx = ;
for (int i=; i<=n; i++)
{
int dl = deal(now-);
int dr = dear(now+);
if (reval(dl) > reval(dr)){
now = dl;
vis[dl] = ;
sum += reval(dl);
}else{
sum += reval(dr);
if (rx < dr){
for (int j=now+; j<=dr; j++) q.push(j);
rx = dr;
}
now = dr;
vis[dr] = ;
}
printf("%d\n",sum);
}
return ;
}

第二次WA

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

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

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

反正都是全WA

 #include<bits/stdc++.h>
using namespace std;
const int N = 1e5;
int n,s[N],w[N],f[N],now,sum,rx;
bool vis[N];
int reval(int a)
{
if (a >= rx)return w[a]+*(s[a]-s[rx]);
return w[a];
}
struct cmp
{
bool operator () (int &a, int &b) const
{
return reval(a) < reval(b);
}
};
priority_queue<int, vector<int>, cmp> p,q;
int deal(int x)
{
if (x <= )return ;
queue<int>tt;
while ((!q.empty())&&(q.top()>now||vis[q.top()]))
{
while ((!q.empty())&&(vis[q.top()]))q.pop();
while ((!q.empty())&&(q.top()>now)){tt.push(q.top());q.pop();}
}
if (q.empty())return ;
int xx = q.top();
while (!tt.empty()){q.push(tt.front());tt.pop();}
return xx;
}
int dear(int x)
{
queue<int>tt;
if (rx == n)return ;
if(rx!=n)while ((!p.empty())&&(p.top()<now||vis[p.top()]))
{
while ((!p.empty())&&(vis[p.top()]))p.pop();
// printf("ptop:%d\n",p.top());
while((!p.empty())&&(p.top()<now)){tt.push(p.top());p.pop();}
}
if (p.empty())return ;
int xx = p.top();
while (!tt.empty()){p.push(tt.front());tt.pop();}
return xx;
}
int main()
{
scanf("%d",&n);
for (int i=; i<=n; i++)scanf("%d",&s[i]);
for (int i=; i<=n; i++){scanf("%d",&w[i]);p.push(i);}
f[n] = n;
for (int i=n-; i>=; i--)
if (*s[i]+w[i] > *s[f[i+]]+w[f[i+]])
f[i] = i;
else f[i] = f[i+];
now = ;rx = ;
// for (int i=1; i<=n; i++)printf("%d ",f[i]);printf("#\n");
for (int i=; i<=n; i++)
{
int dl = deal(now-);
int dr = dear(now+);
// printf("now:%d rx:%d dl:%d %d-dr:%d %d\n",now,rx,dl,reval(dl),dr,reval(dr));
if (reval(dl) >= reval(dr)){
now = dl;
vis[dl] = ;
sum += reval(dl);
}else{
sum += reval(dr);
if (rx < dr){
for (int j=rx+; j<=dr; j++) q.push(j);
rx = dr;
}
now = dr;
vis[dr] = ;
}
// for (int i=1; i<=n; i++)printf("%d ",vis[i]);puts("@");
printf("%d\n",sum);
}
int dl = deal(now-);
int dr = dear(now+);
// printf("now:%d rx:%d dl:%d %d-dr:%d %d\n",now,rx,dl,reval(dl),dr,reval(dr));
return ;
}

第一次TLE

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

 #include<bits/stdc++.h>
using namespace std;
const int N = 1e5+;
int n,s[N],w[N],rx,now,sum;
int a,b;
bool vis[N];
int reval(int x)
{
if (x < rx)return w[x];
return w[x] + *(s[x]-s[rx]);
}
int main()
{
scanf("%d",&n);
for (int i=; i<=n; i++)scanf("%d",&s[i]);
for (int i=; i<=n; i++)scanf("%d",&w[i]);
for (int k=; k<=n; k++)
{
a = , b = ;
int cmp = , lb;
for (int i=; i<now; i++)
if ((!vis[i])&&(a < w[i]))a = w[b = i];
cmp = a;lb = b;
a = ,b = ;
for (int i=now+; i<=n; i++)
if ((!vis[i])&&(a < reval(i)))
a = reval(i),b = i;
if (a > cmp){cmp = a;lb = b;}
rx = max(rx, lb);
vis[lb] = ;
now = lb;
sum += cmp;
printf("%d\n",sum);
}
return ;
}

正解AC

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

 #include<bits/stdc++.h>
using namespace std;
const int N = 1e5+;
int n,s[N],w[N],rx,now,sum;
int a,b;
bool vis[N];
struct cmp
{
bool operator() (int &a, int &b)
{
return w[a] < w[b];
}
};
priority_queue<int, vector<int>, cmp>q;
void find()
{
while ((!q.empty())&&(vis[q.top()]))q.pop();
if (q.empty())return;
b = q.top();a = w[b];
}
int main()
{
scanf("%d",&n);
for (int i=; i<=n; i++)scanf("%d",&s[i]);
for (int i=; i<=n; i++)scanf("%d",&w[i]);
for (int k=; k<=n; k++)
{
a = , b = ;
int cmp = , lb;
find();
cmp = a;lb = b;
a = ,b = ;
for (int i=rx+; i<=n; i++)
if ((!vis[i])&&(a < w[i] + *(s[i]-s[rx])))
a = w[i] + *(s[i]-s[rx]),b = i;
if (a > cmp)
{
cmp = a;
lb = b;
}
if (rx < lb)
{
for (int i=rx+; i<=lb; i++)q.push(i);
rx = lb;
}
vis[lb] = ;
now = lb;
sum += cmp;
printf("%d\n",sum);
}
return ;
}

【贪心 堆】luoguP2672 推销员的更多相关文章

  1. 【贪心+堆】XMU 1584 小明的烦恼

    题目链接: http://acm.xmu.edu.cn/JudgeOnline/problem.php?id=1584 题目大意: 给n(n<=100 000)个任务的耗时和截至时间,问最少不能 ...

  2. BZOJ_2151_种树_贪心+堆+链表

    BZOJ_2151_种树_贪心+堆 Description A城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树.园林部门得到指令后,初步规划出n个种树的位置,顺时针编 ...

  3. BZOJ_2006_[NOI2010]超级钢琴_贪心+堆+ST表

    BZOJ_2006_[NOI2010]超级钢琴_贪心+堆+ST表 Description 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的 音乐 ...

  4. BZOJ_1029_ [JSOI2007]建筑抢修_贪心+堆

    BZOJ_1029_ [JSOI2007]建筑抢修_贪心+堆 Description 小刚在玩JSOI提供的一个称之为“建筑抢修”的电脑游戏:经过了一场激烈的战斗,T部落消灭了所有z部落的入侵者.但是 ...

  5. 【bzoj4425】[Nwerc2015]Assigning Workstations分配工作站 贪心+堆

    题目描述 佩内洛普是新建立的超级计算机的管理员中的一员. 她的工作是分配工作站给到这里来运行他们的计算研究任务的研究人员. 佩内洛普非常懒惰,不喜欢为到达的研究者们解锁机器. 她可以从在她的办公桌远程 ...

  6. 【bzoj1029】[JSOI2007]建筑抢修 贪心+堆

    题目描述 小刚在玩JSOI提供的一个称之为“建筑抢修”的电脑游戏:经过了一场激烈的战斗,T部落消灭了所有z部落的入侵者.但是T部落的基地里已经有N个建筑设施受到了严重的损伤,如果不尽快修复的话,这些建 ...

  7. 【bzoj2802】[Poi2012]Warehouse Store 贪心+堆

    题目描述 有一家专卖一种商品的店,考虑连续的n天.第i天上午会进货Ai件商品,中午的时候会有顾客需要购买Bi件商品,可以选择满足顾客的要求,或是无视掉他.如果要满足顾客的需求,就必须要有足够的库存.问 ...

  8. BZOJ 1724: [Usaco2006 Nov]Fence Repair 切割木板 贪心 + 堆 + 反向思考

    Description Farmer John想修理牧场栅栏的某些小段.为此,他需要N(1<=N<=20,000)块特定长度的木板,第i块木板的长度为Li(1<=Li<=50, ...

  9. NOIP2015 T4 推销员 贪心+堆优化

    前几天在学堆,这个数据结构貌似挺简单的,但是我看了很久啊QAQ... 今天算是搞懂了吧...于是想到了这道题...(当初悄悄咪咪看题解记得一点) 点我看题 放洛谷的题... 题意的话,大概就是有n个房 ...

随机推荐

  1. hyperledger fabric 1.0.5 分布式部署 (三)

    本篇博客主要是向读者介绍 fabric 在部署时的一些细节,还有作者自己学习过程中的心得. 初始化相关密钥的程序,实际上是一个shell脚本,并且结构特别简单 generateArtifacts.sh ...

  2. AndroidTV开发

    AndroidTV的开发其实和Android的开发是一样的,现在的电视机可以安装AnroidApp

  3. Win7下Intellij开发Scala环境搭建

    1.Scala下载并安装 1.Scala的安装时需要依赖JDK的,目前我的电脑上,jdk是已经安装好了,这里就不再说明 2.在地址http://www.scala-lang.org/download/ ...

  4. 牛客练习赛42B(异或的性质)

    传送门 b^ c >= b - c,这个结论应该记住,我还在这里证过…… 这个题就用到了这个结论,假如当前答案集合为S,和为a,异或和为b,当前答案为a+b了.这时又读入个c,该不该加进来?a ...

  5. 在 Linux 环境直接复移动硬盘上的 GRUB

    手头有一块用了 10 年的旧移动硬盘,其中安装了 Debian 系统,从低版本一直升级到现在的 9 已经用了很长时间.前不久正连着那块硬盘跑着 Debian 修改文件的时候,由于一个本可避免的意外震动 ...

  6. HDU 5230 ZCC loves hacking 大数字的整数划分

    http://acm.hdu.edu.cn/showproblem.php?pid=5230 把题目简化后,就是求 1---n - 1这些数字中,将其进行整数划分,其中整数划分中不能有重复的数字,如果 ...

  7. Solr查询中涉及到的Cache使用及相关的实现【转】

    转自:http://www.cnblogs.com/phinecos/archive/2012/05/24/2517018.html 本文将介绍Solr查询中涉及到的Cache使用及相关的实现.Sol ...

  8. hdu4578Transformation(线段树多个lz标记)

    这里以3次方来举例讲一下这题的做法,其它维类似. 如果要求某一个值的3次方那么sum = t^3,设t = x+y.那也就是sum = (x+y)^3. 假如我让每个数都加z t = x+y+z,我可 ...

  9. 用户会话跟踪机制(session+cookie)

    最近在优化之前给学校写的一个项目,发现了同一个浏览器(IE,Firefox)开多个选项卡的时候不能登录多个用户,后一个登录用户会把前一个用户给覆盖了,我的登录逻辑是把user对象存放到session中 ...

  10. chrome浏览器之网络面板

    这篇指导向你展示怎样检测网络张状况或者在chrome开发工具的网络面板中尽可能的优化网页. 排列的或受阻的请求 症状:同时发出六个请求.之后有一系列的请求排队或受阻.一旦最先的六个请求中有一个响应结束 ...