P5468 [NOI2019]回家路线
看题目一眼斜率优化,然后写半天调不出来
结果错误的 $dfs$ 有 $95$ 分?暴力 $SPFA$ 就 $AC$ 了?
讲讲正解:
显然是斜率优化的式子:
先不考虑 $q_{s_k}$ 的贡献,设 $f[i]$ 表示当前时间为 $i$ 的最小代价
如果不考虑位置关系,有 $f[p_i]=f[q_j]+A(p_i-q_j)^2+B(p_i-q_j)+C$
拆开来:$f[p_i]=f[q_j]+Ap_i^2-2Ap_iq_j+Aq_j^2+Bp_i-Bq_j+C$
换一下位置 $2Ap_iq_j+f[p_i]-Ap_i^2-Bp_i-C=f[q_j]+Aq_j^2-Bq_j$
那么 $k=2Ap_i,x=q_j,b=f[p_i]-Ap_i^2-Bp_i-C,y=f[q_j]+Aq_j^2-Bq_j$
显然直接斜率优化
但是有位置和时间关系,不妨把每列车按时间拆成两点 $p,q$ 分别对应询问和插入,然后按时间拍好序
这样每列车出发时,时间在它之前到达的车都处理完了,可以直接计算贡献,在每列车到达时,再把新的贡献插入凸包
因为还有位置的限制关系,所以对每个位置开一个 $vector$ 维护对应位置的凸包
然后就是具体的实现细节了...
发现维护凸包时是从右边插入,左边弹出,插入可以直接用 $vector$ 的 $push\_back,pop\_back$
左边弹出可以对每个 $vector$ 维护一个变量 $pos$ 表示当前最左的合法点
对最终答案的更新可以在更新 $dp$ 数组时特判
然后就要注意各种细节问题了(调到吐血)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
typedef long long ll;
inline int read()
{
int x=,f=; char ch=getchar();
while(ch<''||ch>'') { if(x=='-') f=-; ch=getchar(); }
while(ch>=''&&ch<='') { x=(x<<)+(x<<)+(ch^); ch=getchar(); }
return x*f;
}
const int N=4e5+,INF=2e9+;
int n,m,A,B,C,ans=INF,pos[N],val[N];//val维护每列火车的贡献
inline int calc(int t) { return A*t*t+B*t+C; }
struct Train{//列车
int x,y,p,q;
}T[N];
struct dat{//按时间排序的点
int tim,type,id;//type判断插入还是查询,id是火车编号
inline bool operator < (const dat &tmp) const {
return tim<tmp.tim;
}
}D[N];
struct datt{//凸包的点
int tim,res;//时间,已经产生的代价
inline int X() { return tim; }
inline int Y() { return res-A*tim*tim-B*tim; }
};
vector <datt> V[N];//vector维护凸包
inline ll Cross(ll xa,ll xb,ll ya,ll yb) { return xa*yb-xb*ya; }//叉积判断直线之间的关系
inline int Y(int p) { return val[p]-A*T[p].q*T[p].q-B*T[p].q; }
inline void push(int p)//插入
{
int t=T[p].y; if(val[p]>=INF) return;//注意特判
while(int(V[t].size())-pos[t]>=)//记得-pos[t]
{
int len=V[t].size();
if( Cross( T[p].q-V[t][len-].X() , Y(p)-V[t][len-].Y() , V[t][len-].X()-V[t][len-].X() , V[t][len-].Y()-V[t][len-].Y() ) < )
break;
V[t].pop_back();//vector自带函数
}
V[t].push_back((datt){T[p].q,val[p]});//加入
}
int main()
{
//freopen("route.in","r",stdin);
//freopen("route.out","w",stdout);
n=read(),m=read(),A=read(),B=read(),C=read();
int a,b,c,d,tot=;
for(int i=;i<=m;i++)
{
a=read(),b=read(),c=read(),d=read();
T[i]=(Train){a,b,c,d};
D[++tot]=(dat){c,,i}; D[++tot]=(dat){d,,i};//把列车拆成两个点
}
sort(D+,D+tot+); V[].push_back((datt){,});//记得插入初始的点
memset(val,0x7f,sizeof(val)); val[]=;//注意val是0x7f,加一点就会爆int
for(int i=;i<=tot;i++)
{
int p=D[i].id,t=T[p].x;
if(D[i].type) { push(p); continue; }
while(int(V[t].size())-pos[t]> && V[t][pos[t]].res+calc(D[i].tim-V[t][pos[t]].tim) >= V[t][pos[t]+].res+calc(D[i].tim-V[t][pos[t]+].tim) )
pos[t]++;
if(pos[t]<int(V[t].size())) val[p]=V[t][pos[t]].res+calc(D[i].tim-V[t][pos[t]].tim);//更新val
if(T[p].y==n&&val[p]<INF) ans=min(ans,val[p]+T[p].q);//注意有些火车坐不上,而val如果是0x7f,加上一个值就会爆掉
}
printf("%d\n",ans);
return ;
}
顺便附上最暴力无脑的 $SPFA$:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
inline int read()
{
int x=,f=; char ch=getchar();
while(ch<''||ch>'') { if(x=='-') f=-; ch=getchar(); }
while(ch>=''&&ch<='') { x=(x<<)+(x<<)+(ch^); ch=getchar(); }
return x*f;
}
const int N=1e5+,M=,INF=2e9+;
struct Train{
int x,y,p,q;
}T[N<<];
struct dat{
int pos,tim;
};
queue <dat> Q;
vector <int> V[N];
int n,m,A,B,C,ans=INF;
inline int clac(int t) { return A*t*t+B*t+C; }
int dis[N][M];
bool vis[N][M];
int main()
{
freopen("route.in","r",stdin);
freopen("route.out","w",stdout);
n=read(),m=read(),A=read(),B=read(),C=read();
int a,b,c,d;
for(int i=;i<=m;i++)
{
a=read(),b=read(),c=read(),d=read();
T[i]=(Train){a,b,c,d};
V[a].push_back(i);
}
memset(dis,0x7f,sizeof(dis));
Q.push((dat){,}); vis[][]=; dis[][]=;
while(!Q.empty())
{
dat x=Q.front(); Q.pop(); vis[x.pos][x.tim]=;
int len=V[x.pos].size();
for(int i=;i<len;i++)
{
int &p=V[x.pos][i]; if(x.tim>T[p].p) continue;
int cst=clac(T[p].p-x.tim);
if(dis[T[p].y][T[p].q]>dis[x.pos][x.tim]+cst)
{
dis[T[p].y][T[p].q]=dis[x.pos][x.tim]+cst;
if(!vis[T[p].y][T[p].q]) Q.push((dat){T[p].y,T[p].q}),vis[T[p].y][T[p].q]=;
}
}
}
for(int i=;i<=m;i++) if(T[i].y==n) ans=min(ans,dis[n][T[i].q]+T[i].q);
printf("%d\n",ans);
return ;
}
SPFA
P5468 [NOI2019]回家路线的更多相关文章
- P5468 [NOI2019]回家路线 斜率优化 dp
LINK:回家路线 (文化课 oi 双爆炸 对 没学上的就是我.(我错了不该这么丧的. 不过还能苟住一段时间.当然是去打NOI了 这道题去年同步赛的时候做过.不过这里再次提醒自己要认真仔细的看题目 不 ...
- 【题解】Luogu P5468 [NOI2019]回家路线
原题传送门 前置芝士:斜率优化 不会的可以去杜神博客学 这道题我考场上只会拆点跑最短路的70pts做法 后来回家后发现错误的爆搜都能拿满分(刀片) 还有很多人\(O(mt)\)过的,还是要坚持写正解好 ...
- Luogu P5468 [NOI2019]回家路线 (斜率优化、DP)
题目链接: (luogu) https://www.luogu.org/problemnew/show/P5468 题解: 爆long long毁一生 我太菜了,这题这么简单考场上居然没想到正解-- ...
- [NOI2019]回家路线
[NOI2019]回家路线 题目大意: 有\(n\)个站点,\(m\)趟车,每趟车在\(p_i\)时从\(x_i\)出发,\(q_i\)时到达\(y_i\). 若小猫共乘坐了\(k\)班列车,依次乘坐 ...
- NOI2019 回家路线 DP
「NOI2019」回家路线 链接 loj 思路 f[i][j]第i个点,时间为j,暴力转移 复杂度O(m*t),好像正解是斜率优化,出题人太不小心了233 代码 #include <bits/s ...
- 【斜率优化】【P5468】 [NOI2019]回家路线
Description 给定 \(n\) 点,这 \(n\) 个点由 \(m\) 班列车穿插连结.对于第 \(i\) 班列车,会在 \(p_i\) 时刻从 \(x_i\) 站点出发开向 \(y_i\) ...
- [NOI2019]回家路线(最短路,斜率优化)
终于把这鬼玩意弄完了-- 为什么写的这么丑-- (顺便吐槽 routesea) 最短路的状态很显然:\(f[i]\) 表示从第 \(i\) 条线下来的最小代价. 首先明显要把那个式子拆开.直觉告诉我们 ...
- luogu 5468 [NOI2019]回家路线 最短路/暴力
想写一个 70 pts 算法,结果数据水,直接就切了 最短路: // luogu-judger-enable-o2 #include<bits/stdc++.h> using namesp ...
- LOJ 3156: 「NOI2019」回家路线
题目传送门:LOJ #3156. 题意简述: 有一张 \(n\) 个点 \(m\) 条边的有向图,边有两个权值 \(p_i\) 和 \(q_i\)(\(p_i<q_i\))表示若 \(p_i\) ...
随机推荐
- k8s基本概念
1)Master模块简介: Master是Cluster的大脑,它的主要职责是调度,即决定将应用放在哪里运行.Master运行Linux操作系统,可以是物理机或者虚拟机.为了实现高可用,可以运 ...
- BZOJ2588 树上静态第k大
题意翻译 给你一棵有n个结点的树,节点编号为1~n. 每个节点都有一个权值. 要求执行以下操作: U V K:求从节点u到节点v的第k小权值. 输入输出格式 输入格式 第一行有两个整数n和m(n,m≤ ...
- j函数 判断以 什么开头
1.str.charAt(index) 返回字符串中指定位置的字符. str 是字符串 我们要将获得的数据 转化为字符串 var code = res.statusCode.toString(); ...
- java程序员必知的 8大排序
Java常用的八种排序算法与代码实现 排序问题一直是程序员工作与面试的重点,今天特意整理研究下与大家共勉!这里列出8种常见的经典排序,基本涵盖了所有的排序算法. 1.直接插入排序 我们经常会到这样一类 ...
- mac上如何搜索文件?
在Mac上如果你用会了搜索功能那绝对是个事半功倍的技巧.因为Mac本身有强大的文件索引能力, 可以帮你快速的找到你需要的文件.就好比我要找到上周修改过的word文档应该怎么办? * 使用语音命令让Si ...
- LeetCode--055--跳跃游戏(java)
给定一个非负整数数组,你最初位于数组的第一个位置. 数组中的每个元素代表你在该位置可以跳跃的最大长度. 判断你是否能够到达最后一个位置. 示例 1: 输入: [2,3,1,1,4] 输出: true ...
- JVM虚拟机运行机制
JVM虚拟机运行机制 什么是JVM?虚拟机是物理机器的软件实现.Java是用在VM上运行的WORA(Write Once Run Anywhere)概念而开发的.编译器将Java文件编译为Java . ...
- 十二 windows临界区,其他各种mutex
一.windows临界区 类似于互斥量 == 临界区. 二.多次进入临界区 进入临界区(加锁): 离开临界区(解锁): 同一个线程中windows中相同临界区变量代表的临界区进入(entercirti ...
- Oracle中start with...connect by/start with…connect by prior子句的用法
connect by 是结构化查询中用到的,其基本语法是:select … from tablenamestart with 条件1connect by 条件2where 条件3;例:select * ...
- centos 无界面安装selenium+chrome+chromedirver的设置
配了一中午的,好不容易正好记录下. 1.我的centos的位数 输入rpm -q centos-release 结果:centos-release-7-4.1708.el7.centos.x86_64 ...