「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 ...
随机推荐
- bugku的一道代码审计基础题:eval
首先看到 include "flag.php",第一反应就应该是文件包含 直接先?hello=file:////etc, 然后啥也没 那就再检查一下代码,eval(var_dump ...
- 一行代码完成定时任务调度,基于Quartz的UI可视化操作组件 GZY.Quartz.MUI
前言 之前发布过第一个版本,有兴趣的可以去看看: NET Core 基于Quartz的UI可视化操作组件 GZY.Quartz.MUI 简介 GitHub开源地址:l2999019/GZY.Quart ...
- Sublime Text3快速创建HTML5框架
输入html:5 按tab键即可
- vue从入门到精通之【vuex】(七)
vue从入门到精通之[vuex](七) vuex一个公用的大仓库,Vuex 可以帮助我们管理共享状态,并附带了更多的概念和框架. Vuex 实现了一个单向数据流,在全局拥有一个 state 存放数据, ...
- 【MySQL作业】MySQL函数——美和易思数学函数和控制流函数应用习题
点击打开所使用到的数据库>>> 1.添加一条商品记录. 商品编码 goodsCode 商品名 goodsName 种类 category 单价 unitPrice 02005 夏 ...
- Salesforce LWC学习(三十九) lwc下quick action的recordId的问题和解决方案
本篇参考: https://developer.salesforce.com/docs/component-library/bundle/force:hasRecordId/documentation ...
- cpu负载
查看cpu负载,我们经常会使用top,或者是uptime命令 但是这只能看到cpu的总体的负载情况.如果我们想看cpu每个核心的负载情况是看不到的. 所以我们可以用mpstat命令 服务器一共32核心 ...
- 微信小程序--数据共享与方法共享
目录 全局数据共享 Mobox npm安装及其注意事项 小程序对 npm 的支持与限制 npm 依赖包的安装与使用 Mobox 1. 全局数据共享 2. 小程序中的全局数据共享方案 3. 使用mobx ...
- python的赋值、浅拷贝和深拷贝
""" 一.赋值在python中就是简单的对象引用 """ list_a = ["aaa", "bbb&quo ...
- 建造者模式(python)
建造者模式将复杂对象的构建与其表示分离.建造者模式主要有两个参与者:建造者(builder)和指挥者(director) 来自为知笔记(Wiz)