当前位置: 首页 > news >正文

(倍增)洛谷 P1613 跑路/P4155 国旗计划

倍增就是把一步一步跳,变成每次跳 2k2^k2k,把 O(n)O(n)O(n)O(log⁡n)O(\log n)O(logn),提高效率。经典应用是求 lca,以下是核心代码,详见洛谷 P3397。

void dfs(ll u,ll fa)
{dep[u]=dep[fa]+1;f[u][0]=fat[u]=fa;for(int i=1;(1<<i)<=dep[u];i++)f[u][i]=f[f[u][i-1]][i-1];for(int i=head[u];i;i=e[i].next){ll v=e[i].to;if(v==fa)continue;dfs(v,u);}
}
ll lca(ll x,ll y)
{if(dep[x]<dep[y])swap(x,y);for(int i=18;i>=0;i--)if(dep[x]-(1<<i)>=dep[y])x=f[x][i];if(x==y)return x;for(int i=18;i>=0;i--){if(f[x][i]!=f[y][i]){x=f[x][i];y=f[y][i];}}return f[x][0];
}
ll dis(ll x,ll y)
{return dep[x]+dep[y]-dep[lca(x,y)]*2;
}

倍增除了求 lca 向上跳之外,在很多题目都会用到倍增思想。

1.洛谷 P1613 跑路

题意

小 A 买了一个空间跑路器,每秒钟可以跑 2t2^t2t 千米(ttt 是任意自然数),可以无限次使用。小 A 的家到公司的路可以看做一个有向图,小 A 家为点 111,公司为点 nnn,每条边长度均为一千米。小 A 想每天能醒地尽量晚,所以让你帮他算算,他最少需要几秒才能到公司。数据保证 111nnn 至少有一条路径。

2≤n≤502\leq n \leq 502n50m≤104m \leq 10 ^ 4m104,最优解路径长度 ≤\leq LONG_LONG_MAX

思路

nnn 的数据范围令人心安,求最短路 Floyd 或者 spfa 随便用。但是这里有个跑路器,所以我们要先处理利用跑路器可以一秒走过的边

我们同样可以用 Floyd 的思想处理跑路器的影响:设 disu,vdis_{u,v}disu,v 表示 uuuvvv 的最短时间,设 fi,j,tf_{i,j,t}fi,j,t 表示,从 iiijjj 是否存在一条长度为 2t2^t2t 的最短路径。如果 ∃fi,j,t=1\exist f_{i,j,t}=1fi,j,t=1,那么 disu,v=1dis_{u,v}=1disu,v=1;否则 disu,v=infdis_{u,v}=\text{inf}disu,v=inf

考虑 fff 的转移:枚举跑路器参数 ttt 和一个中间点 kkk(先枚举 ttt 是要保证 1∼t−11\sim t-11t1 已经处理完毕),如果分别 ∃fi,k,t−1=fk,j,t−1=1\exist f_{i,k,t-1}=f_{k,j,t-1}=1fi,k,t1=fk,j,t1=1,那么把这两段拼起来,可以用一次 2t2^t2t 的跑路器,同时 disi,j=1dis_{i,j}=1disi,j=1

最后开心地 Floyd 就好了,答案就是 dis1,ndis_{1,n}dis1,n

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=52,M=66,inf=0x3f3f3f3f;
ll n,m;
ll dis[N][N];
bool f[N][N][M];//s到t是否存在2^i路径 
void init()
{for(int t=1;t<=64;t++)for(int k=1;k<=n;k++)for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(f[i][k][t-1]&&f[k][j][t-1])f[i][j][t]=1,dis[i][j]=1;
}
int main()
{memset(dis,inf,sizeof(dis));scanf("%lld%lld",&n,&m);for(int i=1;i<=m;i++){ll u,v;scanf("%lld%lld",&u,&v);dis[u][v]=1;f[u][v][0]=1;}init();for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)for(int k=1;k<=n;k++)dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);printf("%lld",dis[1][n]);return 0;
}

2.洛谷 P4155 国旗计划

题意

A 国正在开展国旗计划,内容是边防战士手举国旗环绕边境线奔袭一圈,需要多名边防战士以接力的形式共同完成。为此,国土安全局已经挑选了 NNN 名优秀的边防战士作为这项计划的候选人。

A 国边境线上设有 MMM 个边防站,顺时针编号 111MMM。每名边防战士常驻两个边防站,并且善于在这两个边防站之间长途奔袭,我们称这两个边防站之间的路程是这个边防战士的奔袭区间。NNN 名边防战士都是精心挑选的,身体素质极佳,所以每名边防战士的奔袭区间都不会被其他边防战士的奔袭区间所包含。

局长希望知道,至少需要多少名边防战士,才能使得他们的奔袭区间覆盖全部的边境线,从而顺利地完成国旗计划。不仅如此,安全局局长还希望知道更详细的信息:对于每一名边防战士,在他必须参加国旗计划的前提下,至少需要多少名边防战士才能覆盖全部边境线,从而顺利地完成国旗计划。

N≤2×105,M<109N\leq 2×10^5,M<10^9N2×105,M<109

思路

先破环成链。

两个战士可以接力,需要两个战士的区间有交(存在一个点分别属于两个战士的区间)。

处理每个被固定选定的 nnn 个战士,如果遍历所有战士就去到 O(n2)O(n^2)O(n2) 了。那当然要优化处理,肯定是不能一个一个跳的,那么可以尝试倍增。

fi,kf_{i,k}fi,k 表示从战士 iii 出发,合法地接力了 2k2^k2k 个战士,到达了哪一个边防战士。先 O(n)O(n)O(n) 处理 fi,0f_{i,0}fi,0,然后传统的倍增操作即可,O(2nlog⁡2n)O(2n\log2n)O(2nlog2n)

void init()
{ll nxt=1;for(int i=1;i<=nn;i++){while(nxt<=nn&&a[nxt].l<=a[i].r)nxt++;//最远的可以转接 f[i][0]=nxt-1;}for(int i=1;(1<<i)<=n;i++)for(int s=1;s<=nn;s++)f[s][i]=f[f[s][i-1]][i-1];
}

对于每个战士,我们从高到低枚举 kkk 来跳。对于一个战士 pospospos,如果rpos≥lstart+mr_{pos}\ge l_{start}+mrposlstart+m,就是走完了一圈。最后记得加上自己和闭环的战士就好了。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=4e5+9,M=20;
ll n,nn,m;
struct node
{ll l,r,id;
}a[N];
bool cmp(node x,node y)
{return x.l<y.l;
}
ll f[N][M];
void init()
{ll nxt=1;for(int i=1;i<=nn;i++){while(nxt<=nn&&a[nxt].l<=a[i].r)nxt++;//最远的可以转接 f[i][0]=nxt-1;}for(int i=1;(1<<i)<=n;i++)for(int s=1;s<=nn;s++)f[s][i]=f[f[s][i-1]][i-1];
}
ll ans[N];
void cal(ll x)
{ll tot=1,cur=x;for(int i=M-1;i>=0;i--){ll pos=f[cur][i];if(pos&&a[pos].r<a[x].l+m){cur=pos;tot+=(1<<i);}}ans[a[x].id]=tot+1;//闭环 
} 
int main()
{scanf("%lld%lld",&n,&m);for(int i=1;i<=n;i++){ll l,r;scanf("%lld%lld",&l,&r);if(r<l)r+=m;a[i]=(node){l,r,i};}sort(a+1,a+n+1,cmp);nn=n;for(int i=1;i<=n;i++){nn++;a[nn].l=a[i].l+m;a[nn].r=a[i].r+m;}init();for(int i=1;i<=n;i++)cal(i);for(int i=1;i<=n;i++)printf("%lld ",ans[i]);return 0;
}
http://www.dtcms.com/a/268856.html

相关文章:

  • VBA之Word应用第三章第十一节:Document对象的事件
  • 图像采集卡选型详细指南
  • SAP HANA内存数据库解析:特性、优势与应用场景 | 技术指南
  • OceanBase在.NET开发操作指南
  • 5、Receiving Messages:Message Listener Containers
  • 【Note】《Kafka: The Definitive Guide》第7章 Building Data Pipelines
  • 【牛客刷题】实现返回最大的不大于n的完美数的函数
  • [NOIP][C++]洛谷P1035 [NOIP 2002 普及组] 级数求和
  • 牛客周赛 Round 99 EF
  • 【PTA数据结构 | C语言版】求两个正整数的最大公约数
  • Camera相机人脸识别系列专题分析之十六:人脸特征检测FFD算法之libcvface_api.so数据结构详细注释解析
  • 芯谷科技--高性能双通道音频功率放大器D7050
  • LabVIEW与FPGA超声探伤
  • 单细胞数据格式转换:rds 与 h5ad互转
  • 倒排索引(Inverted Index)深度解析
  • uniapp跳转页面时如何带对象参数
  • 后端微服务基础架构Spring Cloud
  • UI前端与数字孪生融合新领域:智慧旅游的可视化导览系统
  • kong网关基于header分流灰度发布
  • Linux手动安装MySQL(基于CentOS 7 X86)
  • HCI接口协议:主机与控制器通信的标准桥梁(面试深度解析)
  • Ubunt20.04搭建GitLab服务器,并借助cpolar实现公网访问
  • Taro+Vue3实现微信小程序富文本编辑器组件开发指南
  • RoboRefer:面向机器人视觉-语言模型推理的空间参考
  • 数学建模从入门到国奖——备赛规划优秀论文学习方法
  • 在 Windows 系统上配置 [go-zero](https://go-zero.dev) 开发环境教程
  • React-React.memo-props比较机制
  • 基于YOLOv11的车辆检测系统项目教程(Python源码+Flask Web界面+数据集)
  • AI智能体长期记忆系统架构设计与落地实践:从理论到生产部署
  • [论文阅读] 人工智能 | 读懂Meta-Fair:让LLM摆脱偏见的自动化测试新方法