「IOI2009」旅行商
首先,看到这道题感觉就像dp(然鹅没什么用)。
一个美好的设想
假如没有两个展销会在同一天开展:前途光明
暴力dp,复杂度o(\(n^2\))。
没有同一天的展销会
暴力dp慢,是因为本质上很多状态都是没有什么用的(或者说可以压缩)。
那么可以考虑将一个区间的信息压缩到点上。

先把一段区间均分为左半部分和右半部分。
假如A这个点有展销会,那么左半部分就会向右走。
考虑把左半部分的信息压缩到端点,这个还是比较简单的,如果左半部分有开展过展销会,那么顺便把左右端点的值给更新掉。这样就快速的将左半部分的值转移到A点。

再转到剩下右半部分。
继续把区间切成两半,同理将右半部分的信息转移到A点,对左半部分进行递归处理。
那么现在假设A点已经处理好了。要进行信息的更新。
首先,左右端点肯定是需要的。对于切割点同样也要更新(仅仅更新左右端点是无法处理这种情况的)。
于是一个展销会就被处理好了,一次的复杂度为o(log(n))。
有同一天的展销会
还是要面对有展销会在同一天的事实。。。
其实,同一天的展销会可以按照所在位置进行排序,然后按照某个顺序dp下去(我总不可能先←再→然后←,明显的浪费钱),所以只要正序,倒序各自dp一遍即可。
然而信息不能相互干扰,所以需要一个中间数组来存储某一个顺序的dp结果(当然不需要全部的信息,只需要展销会所在的点,再另行更新),而另一顺序直接放到原数组里就好了。
由于这个写法保证了每个点都会包括到一个或多个可以更新答案的点(并且保证可以以最优的方式转移),所以直接按顺序dp下来并没有什么问题(相当于先移动到一个点,再单方向移动,囊括了 先←再→ 以及 先→再← 的方案)。所以70pts和100pts思路没有区别。
这样这道题就好了 (假装讲明白了)。
code
#include<bits/stdc++.h>
#define unable AC
#define KLL dying
#define re register int
#define rep(q,a,b) for(re q(a),q##_end_(b);q<=q##_end_;++q)
#define dep(q,a,b) for(re q(a),q##_end_(b);q>=q##_end_;--q)
#define mem(a,b) memset(a,b,sizeof a)
using namespace std;
void in(int &r) {
static char c;
r=0;
while(c=getchar(),!isdigit(c));
do r=(r<<1)+(r<<3)+(c^48);
while(c=getchar(),isdigit(c));
}
const int mn=500005;
int val[mn],n,n_cost,s_cost,st;
struct node {
int tim,at,val;
bool operator <(const node &A)const {
return tim==A.tim?at<A.at:tim<A.tim;
}
} qw[mn];
int len_max,Max,at,adv,md[mn];
int dis(int l,int r) {
if(l<r)return (r-l)*s_cost;
return (l-r)*n_cost;
}
void mid_add(int l,int r) {
md[l]=max(md[l],val[l]),md[r]=max(md[r],val[r]);
if(l==r)md[l]=max(md[l],Max+adv);
else {
Max=max(Max,md[l]-dis(l,at));
Max=max(Max,md[r]-dis(r,at));
int mid=l+r>>1;
if(at>mid) {
mid_add(mid+1,r);
md[mid]=max(md[mid],val[mid]);
md[mid]=max(md[mid],md[at]-dis(at,mid));
} else {
mid_add(l,mid);
md[mid+1]=max(md[mid+1],val[mid+1]);
md[mid+1]=max(md[mid+1],md[at]-dis(at,mid+1));
}
md[l]=max(md[l],md[at]-dis(at,l));
md[r]=max(md[r],md[at]-dis(at,r));
}
}
void add(int l,int r) {
if(l==r)val[l]=max(val[l],Max+adv);
else {
Max=max(Max,val[l]-dis(l,at));
Max=max(Max,val[r]-dis(r,at));
int mid=l+r>>1;
if(at>mid) {
add(mid+1,r);
val[mid]=max(val[mid],val[at]-dis(at,mid));
} else {
add(l,mid);
val[mid+1]=max(val[mid+1],val[at]-dis(at,mid+1));
}
val[l]=max(val[l],val[at]-dis(at,l));
val[r]=max(val[r],val[at]-dis(at,r));
}
}
void replace(int l,int r) {
if(l==r)val[l]=max(val[l],adv);
else {
int mid=l+r>>1;
if(at>mid) {
replace(mid+1,r);
val[mid]=max(val[mid],val[at]-dis(at,mid));
} else {
replace(l,mid);
val[mid+1]=max(val[mid+1],val[at]-dis(at,mid+1));
}
val[l]=max(val[l],adv-dis(at,l));
val[r]=max(val[r],adv-dis(at,r));
}
}
void solve() {
rep(q,1,len_max)val[q]=-dis(st,q),md[q]=val[q];
int now=1;
while(now<=n) {
int last=now;
while(qw[now+1].tim==qw[now].tim)++now;
rep(q,last,now) {
Max=-1e9,adv=qw[q].val,at=qw[q].at;
mid_add(1,len_max);
}
dep(q,now,last) {
Max=-1e9,adv=qw[q].val,at=qw[q].at;
add(1,len_max);
}
rep(q,last,now){
adv=md[qw[q].at];
at=qw[q].at;
replace(1,len_max);
}
++now;
}
int ans=0;
rep(q,1,len_max)ans=max(ans,val[q]-dis(q,st));
cout<<ans;
}
int main() {
// freopen("salesman.in","r",stdin);
// freopen("salesman.out","w",stdout);
in(n),in(n_cost),in(s_cost),in(st);
len_max=st;
rep(q,1,n)in(qw[q].tim),in(qw[q].at),in(qw[q].val),len_max=max(len_max,qw[q].at);
sort(qw+1,qw+n+1);
solve();
return 0;
}
「IOI2009」旅行商的更多相关文章
- 「SCOI2014」方伯伯的商场之旅 解题报告
「SCOI2014」方伯伯的商场之旅 我一开始的想法会被两个相同的集合位置去重给搞死,不过应该还是可以写的,讨论起来老麻烦. 可以先钦定在\(1\)号点集合,然后往后调整一部分. 具体一点,通过前缀和 ...
- 「SCOI2014」方伯伯的商场之旅
「SCOI2014」方伯伯的商场之旅 题目描述 方伯伯有一天去参加一个商场举办的游戏.商场派了一些工作人员排成一行.每个人面前有几堆石子.说来也巧,位置在 \(i\) 的人面前的第 \(j\) 堆的石 ...
- Bzoj3352 [ioi2009]旅行商
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 89 Solved: 36 Description 旅行商认定如何优化旅行路线是一个非常棘手的计算问题 ...
- Android逆向之旅---静态方式分析破解视频编辑应用「Vue」水印问题
一.故事背景 现在很多人都喜欢玩文艺,特别是我身边的UI们,拍照一分钟修图半小时.就是为了能够在朋友圈显得逼格高,不过的确是挺好看的,修图的软件太多了就不多说了,而且一般都没有水印啥的.相比较短视频有 ...
- 一个「学渣」从零开始的Web前端自学之路
从 13 年专科毕业开始,一路跌跌撞撞走了很多弯路,做过餐厅服务员,进过工厂干过流水线,做过客服,干过电话销售可以说经历相当的“丰富”. 最后的机缘巧合下,走上了前端开发之路,作为一个非计算机专业且低 ...
- 【C#代码实战】群蚁算法理论与实践全攻略——旅行商等路径优化问题的新方法
若干年前读研的时候,学院有一个教授,专门做群蚁算法的,很厉害,偶尔了解了一点点.感觉也是生物智能的一个体现,和遗传算法.神经网络有异曲同工之妙.只不过当时没有实际需求学习,所以没去研究.最近有一个这样 ...
- 「译」JUnit 5 系列:条件测试
原文地址:http://blog.codefx.org/libraries/junit-5-conditions/ 原文日期:08, May, 2016 译文首发:Linesh 的博客:「译」JUni ...
- 「译」JUnit 5 系列:扩展模型(Extension Model)
原文地址:http://blog.codefx.org/design/architecture/junit-5-extension-model/ 原文日期:11, Apr, 2016 译文首发:Lin ...
- JavaScript OOP 之「创建对象」
工厂模式 工厂模式是软件工程领域一种广为人知的设计模式,这种模式抽象了创建具体对象的过程.工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别的问题. function createPers ...
随机推荐
- Boost的反射库PFR
目录 目录 简介 使用方法 限制 总结 简介 Boost.PFR是一个Boost 1.75版本出的C++14的基础反射库,其使用非常简单,非常便捷,但是适用性也比较差,有很多的地方无法使用,适合比较简 ...
- Simplicial principal component analysis for density functions in Bayes spaces
目录 问题 上的PCA Hron K, Menafoglio A, Templ M, et al. Simplicial principal component analysis for densit ...
- 文件挂载(一)- Linux挂载Linux文件夹
一.概述 工作中经常会出现不同服务器.不同操作系统之间文件夹互相挂载的情形,例如文件服务器或数据备份服务器. 挂载一般来说就是以下四种类型: 同类型操作系统 a. linux挂载linux文件夹 b. ...
- CapstoneCS5210|CS5210低BOM成本方案CS5210|HDMI转VGA芯片方案
Capstone最新推出的一款HDMI转VGA音视频转接线或者转换器方案芯片CS5210. 其设计的优势在于内置晶振,外围电路器件较少设计简单,芯片封装集成度较高,方案BOM成本低,相比其他方案产品更 ...
- 编写Java程序,在硬盘中选取一个 txt 文件,读取该文档的内容后,追加一段文字“[ 来自新华社 ]”,保存到一个新的 txt 文件内
查看本章节 查看作业目录 需求说明: 在硬盘中选取一个 txt 文件,读取该文档的内容后,追加一段文字"[ 来自新华社 ]",保存到一个新的 txt 文件内 实现思路: 创建 Sa ...
- 1.spring系列之优雅的实现接口统一返回
好处 现在公司开发基本上都是以前后分离模式为主,所以要有个统一的数据格式,这样有什么好处呢? 能够提高前后端对接的效率(特别重要) 代码更加优雅和简洁 对于前端和后端维护更方便容易 实现(直接上代码) ...
- python爬虫实例——基于python实现有道云翻译接口
# 分析包# 分析post请求中参数# 使用python模拟lts.sign.salt参数运算# 执行结果> > 1.按F12对网页进行分析,填写内容后自动翻译的功能一般是通过ajax实现 ...
- Appium之xpath定位详解
前面也说过appium也是以webdriver为基的,对于元素的定位也基本一致,只是增加一些更适合移动平台的独特方式,下面将着重介绍xpath方法,这应该是UI层元素定位最强大的方法啦! 以淘宝app ...
- Ant 调用 Shell/CMD 命令
Ant中调用Makefile,使用shell中的make命令 <?xml version="1.0" encoding="utf-8" ?> < ...
- 详谈 Java工厂 --- 静态工厂 【简单工厂模式】
1.前言 什么是工厂模式? 就是为了尽可能将代码的耦合度降低而产生的设计模式. 这篇随笔讲解静态工厂的思路和具体操作. 2.总结 (1)静态工厂又称 简单 工厂模式 ,是最最简单的工厂模式. (2)优 ...