把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

题解 P1081 [NOIP2012 提高组] 开车旅行

传送门

题意

显然。

分析

先分析我们的询问。

对于第一个问题,我们可以枚举起点,计算出小 A 的路程总数,小 B 的路程总数,将比值比较即可求到答案、

对于第二个问题,就是某个起点下,最长为 x 的小 A 路程总数,小 B 的路程总数。

因此,我们其实需要的操作只有一个:在某个起点,长度为 x 的小 A 路程总数,小 B 的路程总数。

并且,得到这个操作的时间复杂度应当是 O(logn) 级别的。

先想一下暴力应当如何打。

首先,我们用 O(n2) 的时间复杂度处理出当前节点的最近的节点与次近的节点,然后在每一个操作时,暴力向后跳动,以 O(n) 的时间复杂度解决每一个操作。

inline void init() {
for(int i=1; i<=n; ++i) {
nxt[i][0]=nxt[i][1]=n+1;
for(int j=i+1; j<=n; ++j) {
if(dis(i,j)<dis(i,nxt[i][1])) nxt[i][1]=j;
if(dis(i,j)==dis(i,nxt[i][1])&&h[nxt[i][1]]>h[j]) nxt[i][1]=j;
if(dis(i,nxt[i][0])>dis(i,nxt[i][1])) swap(nxt[i][0],nxt[i][1]);
if(dis(i,nxt[i][0])==dis(i,nxt[i][1])&&h[nxt[i][0]]>h[nxt[i][1]]) swap(nxt[i][0],nxt[i][1]);
}
swap(nxt[i][0],nxt[i][1]);
}
}
int tot[2];
inline node solve(int now,int mx) {
int flag=0;
tot[1]=tot[0]=0;
while(now<=n) {
if(nxt[now][flag]>n) break;
if(tot[1]+tot[0]+dis(nxt[now][flag],now)>mx) break;
tot[flag]+=dis(nxt[now][flag],now);
now=nxt[now][flag];
flag=!flag;
}
return <%tot[0],tot[1]%>;
}

总时间复杂度:O(n×m)。拿下 70pts

接着分析正解。

此时,我们的两个部分都是超出我们的期望时间复杂度的,因此,我们需要分开优化。

一方面,优化预处理。

为了处理出最近的与次近的,我们使用 set 来处理。

因为我们当前节点的最近与次近实则只有当前剩余的数字距离当前节点的最近的几个之一。

因此,实则,我们在处理时只需要寻找在数字上与其相邻的四个节点即可。

此部分时间复杂度:O(nlogn)

再优化询问的时间复杂度,可以发现,我们的暴力是一步一步跳跃的,尽管是有两种跳跃,但是我们不妨令两个合并成一个操作。

最后就可以用倍增来解决。

时间复杂度:O(n×logn)

posted @   djh0314  阅读(16)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
浏览器标题切换
浏览器标题切换end
点击右上角即可分享
微信分享提示