「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 ...
随机推荐
- 1.SpringCloud与Dubbo的区别
1.SpringCloud与Dubbo的区别 初始定位不同: SpringCloud定位为微服务架构下的一站式解决方案:Dubbo 是 SOA 时代的产物,它的关注点主要在于服务的调用和治理 生态环境 ...
- uniapp蓝牙传输中文乱码问题
问题描述:app接收到蓝牙传出过来的二进制数据,1.app进行arrbuff转成16进制字符串 // ArrayBuffer转16进度字符串示例 function ab2hex(buffer) { c ...
- Android开发布局 案例二
实践案例: XML <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:an ...
- CSS基础-4 定位
CSS定位和浮动 css定位:改变页面的位置 定位机制有以下三种 普通流 浮动 绝对布局 定位的属性: position:把元素放在一个静态的.相对的.绝对的.或固定的位置中 top ...
- css 基础 css引入方式
color:red; //改变颜色 font-size:18px : //改变文字大小 background-color : blue; //设置背景颜色 width:100px ://设置宽度 he ...
- [ flask-migrate ] 记自己犯的一次低级错误
问题描述 从github上pull了别人的项目学习,项目用flask-migrate来迁移数据库.查看了一下,作者把数据库文件 app.db 删除了,不过migrations文件夹留着的,因此我只需要 ...
- Spark-2.0.2源码编译
注:图片如果损坏,点击文章链接:https://www.toutiao.com/i6813925210731840013/ Spark官网下载地址: http://spark.apache.org/d ...
- JDBC简单查询数据库
注:图片如果损坏,点击文章链接:https://www.toutiao.com/i6543890367761089031/ 1.我们先新建一个数据库作为测试库 数据库名称为test.测试表为perso ...
- WinMain是如何被调用的
WinMain函数 WinMain函数原型 Win32应用程序的入口函数为WinMain,函数原型在WinBase.h文件中: int WINAPI WinMain ( _In_ HINSTA ...
- XCTF-反序列化中_wakeup()函数
跳过_wakeup()魔法函数__wakeup(): 将在序列化之后立即被调用漏洞原理: 当反序列化字符串中,表示属性个数的值大于其真实值,则跳过__wakeup()执行 对于该题,先可以看到类xct ...