一,概述
倍增法(英语:binary lifting),顾名思义就是翻倍。它能够使线性的处理转化为对数级的处理,大大地优化时间复杂度。
基于使得所需区间由2的整数幂拼凑而成
二,基础应用
- 正序预处理+倒叙拼凑型
1,预处理
f
[
i
]
[
j
]
=
f
[
i
−
1
]
[
f
[
i
−
1
]
[
j
]
]
+
.
.
.
f[i][j]=f[i-1][f[i-1][j]]+...
f[i][j]=f[i−1][f[i−1][j]]+...,与一种Dp类似
2,(从大到小)枚举步长非负数次幂,尝试跳跃并更新现状
应用:线段上任意长度的最值,链上最值,次数这样的信息
事例:ST表,LCA等等
- 变长尺取型
设定初始尺寸:
p
=
1
p=1
p=1
设置初始#位置:
k
=
0
k=0
k=0
1,若是
k
+
p
k+p
k+p满足条件,位置跳出,尺取倍增,
k
+
=
p
k+=p
k+=p,
p
∗
=
2
p*=2
p∗=2
2,若是
k
+
p
k+p
k+p不满足,位置不动,尺取倍减,
p
/
=
2
p/=2
p/=2
3,终止条件:
p
=
=
0
p==0
p==0
- 位运算型
for(int i=0;m;i++)
{
if(m&(1ll<<i))
{
......
m ^= 1ll<<i;
}
}
- 结合二分和整体二分.,dsu…
三,实际例子
0,趣味知识
- 如何用最少砝码称出
[
1
,
31
]
[1,31]
[1,31]的所有重量
1,使用1,2,4,8,16
2,基于倍增的划分,可用进制判断
1, 倍增+最短路
- 考虑和floyd的结合,如果组图中有边且依靠2的整数次幂长度相连,那么就是可达,时间设为1
- 直接floyd最短路
int dis[60][60];
int n,m;
bool G[60][60][66];
void init()
{
ios_base::sync_with_stdio(false);
cin.tie(0);
Mset(G,0);
Mset(dis,0x3f);
cin >> n >> m;
rep(i,1,m)
{
int x,y;
cin >> x >> y;
dis[x][y]=1;
G[x][y][0]=1;
}
}
void work()
{
for(int k=1;k<=64;k++)
for(int i=1;i<=n;i++)
for(int t=1;t<=n;t++)
for(int j=1;j<=n;j++)
if(G[i][t][k-1] && G[t][j][k-1])
{
G[i][j][k] =1;
dis[i][j]=1;
}
}
void floy()
{
rep(k,1,n)
rep(i,1,n)
rep(j,1,n)dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
int main()
{
init();
work();
floy();
cout<<dis[1][n];
}
2,倍增优化DP
链接如下,搞定一道,通透一类!