电子学会八级-数据结构-倍增
倍增思想可以很早学习,有些需要数学基础,所以放到这个级别
应用--二进制拆分
应用一 快速幂
应用二-快速乘
O(1)快速乘
https://www.luogu.com.cn/problem/T105910
#include<bits/stdc++.h>
#define ll long long
using namespace std;
//二进制实现快速乘
/*
偶数相乘 奇数加入ans
8*6=16*3=32*1+16=16+32=48
16先加入ans 最后一次b=1时 ans=ans+a =16+32=48
*/
ll mul_q(ll a,ll b,ll mod){
long long res=0;
while(b){//b>=1指向如下操作 最后一次=1时 把res=res+a
if(b&1)//与1位运算 奇数为1 true 偶数为0 false
res=(res+a)%mod;//奇数时加入ans
a=(a<<1)%mod;//a*2
b>>=1;// b/2
}
return res;
}
int main(){
ll a,b,p;
cin>>a>>b>>p;
ll ans=mul_q(a,b,p);
cout<<ans<<endl;
return 0;
}
猜数字
https://www.luogu.com.cn/problem/P3868
多少个1
https://www.luogu.com.cn/problem/P4884
快速阶乘算法
https://www.luogu.com.cn/problem/P5282
随机数生成器
https://www.luogu.com.cn/problem/P2044
应用三-矩阵乘法
斐波那契数列
https://www.luogu.com.cn/problem/P1962
#include<bits/stdc++.h>
typedef long long ll;
const ll mod=1e9+7;
using namespace std;
/*
https://loj.ac/p/10219
https://matrix.reshish.com/multCalculation.php
2行3列 * 3行2列 =2行2列
input
2 3
1 2 3
3 2 1
2
1 1
2 2
3 3
output
14 14
10 10
*/
struct Matrix{
ll g[3][3];
Matrix(){//构造函数 初始矩阵数据都为0
memset(g,0,sizeof(g));
}//矩阵初始化为0
Matrix operator *(const Matrix &b) const{//重载乘号
Matrix res;//构造新矩阵 并通过构造函数初始化矩阵数据都为0
for(int i=1;i<=2;i++){
for(int j=1;j<=2;j++){
for(int k=1;k<=2;k++){
//两矩阵相乘 必须满足第2矩阵行数=第2矩阵列数
//计算对应两个矩阵单元格 累加到结果矩阵
//新矩阵行有第一个矩阵行决定 列有第2个矩阵列决定
res.g[i][k]=(res.g[i][k]+g[i][j]*b.g[j][k]%mod)%mod;
}
}
}
return res;
}
}a,ans;
/*
a
1 1
1 0
ans 初始化f[1]+f[2]
1 1
0 0
*/
void init(){
a.g[1][1]=1,a.g[1][2]=1,a.g[2][1]=1;
ans.g[1][1]=ans.g[1][2]=1;
}
//x为矩阵相乘次数 参考普通快速幂
void qpow(ll x){//矩阵快速幂
while(x){
if(x&1) ans=ans*a;//奇数 累乘到ans中
a=a*a;//去除偶数后 可以按幂乘 a*a
x>>=1;//x=x/2
}
}
/*
f[i] = 1*f[i-1] + 1*f[i-2]
f[i-1]= 1*f[i-1] + 0*f[i-2]
所以 *代表矩阵乘 矩阵乘可以使用乘法结合率 所以可以如下1 1矩阵
f[i] = 1 1 * f[i-1] = 1 1 * 1 1 * f[i-2]
f[i-1] 1 0 f[i-2] 1 0 1 0 f[i-3]
*/
int main(){
ll n;
cin>>n;
if(n<=2){
cout<<1;
return 0;
}
init();//初始数据
/*
f(1) f(2)项和 * 一个矩阵n-2次 f(n)+f(n-1)
f[1] * 1 1 f[n]
f[2] 1 0 f[n-1]
所以对矩阵就行n-2次相乘 使用快速幂降低时间复杂度
*/
qpow(n-2);
cout<<ans.g[1][1]%mod;//输出第f[n]项结果
return 0;
}
矩阵快速幂
https://www.luogu.com.cn/problem/P3390
【模板】矩阵加速(数列)
https://www.luogu.com.cn/problem/P1939
矩阵乘法
https://www.luogu.com.cn/problem/B2105
【模板】矩阵乘法
https://www.luogu.com.cn/problem/T103763
[国家集训队]矩阵乘法
https://www.luogu.com.cn/problem/P1527
应用四
ST算法
【模板】ST 表
https://www.luogu.com.cn/problem/P3865
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
//f[i][j]表示第i个开始 到i + (2的j次方)的最大值
int f[maxn][50],lc,n,m,L,R;
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){//初始化
scanf("%d",&f[i][0]);
}
// lc=(int)(log(n)/log(2));//logn 以2为底 n的对数作为
lc=log2(n);//以2为底 n的对数 列
for(int j=1;j<=lc;j++){//动态规划创建st表
for(int i=1;i<=n-(1<<j)+1;i++){//n-(1<<j)+1保证i 不出界
f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);//计算左右边界
}
}
for(int i=1;i<=m;i++){
scanf("%d%d",&L,&R);
// int p=int(log(R-L+1)/log(2));
int p=log2(R-L+1); //可计算范围
// f[L][p] f[R-(1<<p)+1][p]
printf("%d\n",max(f[L][p],f[R-(1<<p)+1][p]));//x+(1<<p)-1 = r x=r-(1<<p)+1
}
}
质量检测
https://www.luogu.com.cn/problem/P2251
Balanced Lineup G
https://www.luogu.com.cn/problem/P2880
理想的正方形
https://www.luogu.com.cn/problem/P2216
01 序列
https://www.luogu.com.cn/problem/P7809
区间与除法
https://www.luogu.com.cn/problem/P5629
应用五
LCA 最近公共祖先
【模板】最近公共祖先(LCA)
https://www.luogu.com.cn/problem/P3379
#include <bits/stdc++.h>
using namespace std;
const int N = 500005, M = N * 2;
struct Edge {
int v, nxt;//终点 nxt下一节点
}e[M];//链式前向星存储
int n, m, s, hd[N], ecnt;
//fa[i][j]从树上编号为 i 的节点向上走2的j次方步会走到哪个节点
//dep[i] i节点的深度
int dep[N], fa[N][22], lg[N];
//链式前向星添加边
void add(int u, int v) {
e[++ecnt].v = v;
e[ecnt].nxt = hd[u];
hd[u] = ecnt;
}
//各点的深度和u跳2的j次方的节点
//u 当前节点 fath父节点
void dfs(int u, int fath) {
fa[u][0]=fath;//走2的0次方 即1步走到父节点
dep[u]=dep[fath]+1;//u 节点深度为父节点深度+1
for(int i=1;i<=lg[dep[u]];i++)//lg=log2 循环深度对数 倍增几步走完
fa[u][i]=fa[fa[u][i-1]][i-1];//fa[u][i-1]走一半到达节点q fa[q][i-1]在q基础上继续完成另一半
for(int i=hd[u];i;i=e[i].nxt){//链式前向星 逐层出来
if(e[i].v==fath) continue;//当前节点为父节点即根节点 结束
dfs(e[i].v,u);//继续往下处理
}
}
//x y的最近公共祖先
int lca(int x, int y) {
if(dep[x] < dep[y]) swap(x, y);// x y交换 方便后续逻辑统一处理
while(dep[x] > dep[y])
x = fa[x][lg[dep[x]-dep[y]]];//每次跑2的lg[dep[x]-dep[y]]个节点 一直跳到深度相同
if(x == y) return x;//如果 y正好跳到x点 x即为x y的最近公共祖先
for(int k = lg[dep[x]]; k >= 0; k--)//不断向上跳(lg就是之前说的常数优化)
if(fa[x][k] != fa[y][k])//因为我们要跳到它们LCA的下面一层,所以它们肯定不相等,如果不相等就跳过去
x = fa[x][k], y = fa[y][k];//x y分别跳相同级数
return fa[x][0];//父节点即为最近公共祖先
}
int main(){
scanf("%d %d %d", &n, &m, &s);//n节点的个数 m询问的个数 s根节点编号
for(int i=1;i<=n-1;i++){//n-1条边 存储在链式前向星
int u, v;
scanf("%d %d",&u,&v);
add(u,v);
add(v,u);//无向边
}
for(int i=2;i<=n;i++)//基础log2 存储 保证O(1)获取
lg[i]=lg[i/2]+1;
dfs(s,0);//从根节点开始记录每个节点深度和每个节点跳2的j次方后到达的节点
for(int i=1;i<=m;i++) {
int x,y;
scanf("%d %d",&x,&y);//输入x y
printf("%d\n",lca(x,y));//输出 x y的最近公共祖先
}
return 0;
}
Milk Visits S
https://www.luogu.com.cn/problem/P5836
会议
https://www.luogu.com.cn/problem/P1395
仓鼠找 sugar
https://www.luogu.com.cn/problem/P3398
紧急集合/聚会
https://www.luogu.com.cn/problem/P4281
小猪佩奇爬树
https://www.luogu.com.cn/problem/P5588
倍增floyd,倍增FFT、后缀数组等倍增思想
作者:newcode 更多资源请关注纽扣编程微信公众号
从事机器人比赛、机器人等级考试、少儿scratch编程、信息学奥赛等研究学习