倍增
倍增这个东西非常多玄妙,主要是通过查找2^k来优化复杂度。
今天的题模版题比较多,在理解略困难的前提下要先记住,能用在实际生活中。
1、快速幂
题目描述
给你三个整数 b,p,k,求 b^p modk。
输入格式
输入只有一行三个整数,分别代表 b,p,k
输出格式
输出一行一个字符串 b^p mod k=s,其中 b,p,k 分别为题目给定的值, s 为运算结果。
输入输出样例
输入
2 10 9
输出
2^10 mod 9=7
这道题看似和倍增没什么关系,但是这俩在思想上是有统一性的,快速幂事实上就是通过对p不断除以二以达到优化复杂度的目的,这是一个模版,记住:
#include<cstdio>
using namespace std;
long long int n,p,k;
long long int mi(long long int x,long long int y,long long int z){
long long int res = 1;
while(y){
if(y % 2 == 1) res = res * x % z;
x = x * x % z;
y = y / 2;
}
return res;
}
int main()
{
scanf("%lld %lld %lld" ,&n,&p,&k);
printf("%lld^%lld mod %lld=%lld" ,n,p,k,mi(n,p,k) % k);
return 0;
}
2、ST表
这是一道ST表经典题——静态区间最大值
给定一个长度为 N 的数列,和 M 次询问,求出每一次询问的区间内数字的最大值。
这道题其实没啥好说的了,就是一个理解加记忆的过程,其实就相当于你把一个大区间分成两个小的(保证小的合起来能覆盖到大的),那么小区间最大值的最大值就是大区间的最大值
#include<cstdio>
#include<algorithm>
using namespace std;
int a[1000001] = { };
int ans[1000001] = { };
int dp[100501][17] = { };
int que[100501] = { };
int m,n;
int query(int l,int r){
int k = que[r - l + 1];
return max(dp[l][k],dp[r - (1 << k) + 1][k]);
}
int main(){
scanf("%d %d" ,&n,&m);
for(int i = 1;i <= n; i++){
scanf("%d" ,&a[i]);
}
for(int i = 1;i <= n; i++){
dp[i][0] = a[i];
}
for(int j = 1;1 << j <= n; ++j){
for(int i = 1;i + (1 << j) - 1 <= n; ++i){
dp[i][j] = max(dp[i][j - 1],dp[i + (1 << (j - 1))][j - 1]);
}
}
int k = 0;
for(int i = 1;i <= n; ++i){
if((1 << k) <= i) k++;
que[i] = k - 1;
}
int h = 1;
for(int i = 1;i <= m; i++){
int x,y;
scanf("%d %d" ,&x,&y);
printf("%d\n" ,query(x,y));
}
return 0;
}
3、理想正方形
这道题是刚刚的升级版,就相当于是二维的ST表,按照刚刚的步骤,把二维数组改为三位的计算即可
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int a,b,n;
int ma[1010][1010][9] = { },mi[1010][1010][9] = { };
int que[1001] = { };
int ans[1010][1010] = { };
int ac[1010][1010] = { };
int max4(int a,int b,int c,int d){
return max(a,max(b,max(c,d)));
}
int min4(int a,int b,int c,int d){
return min(a,min(b,min(c,d)));
}
int l[1001] = { };
int p1 = 0;
int query(int x,int y){
// int k = que[y - x + 1];
int p,q;
p=max4(ma[x][y][p1],ma[x + n - l[p1]][y][p1],ma[x][y + n - (1 << p1)][p1],ma[x + n - (1 << p1)][y + n - (1 << p1)][p1]);
q=min4(mi[x][y][p1],mi[x + n - (1 << p1)][y][p1],mi[x][y + n - (1 << p1)][p1],mi[x + n - (1 << p1)][y + n - (1 << p1)][p1]);
return p - q;
}
int main(){
scanf("%d %d %d" ,&a,&b,&n);
for(int i = 1;i <= a; i++){
for(int j = 1;j <= b; j++){
scanf("%d" ,&ac[i][j]);
}
}
for(int i = 1;i <= a; i++){
for(int j = 1;j <= b; j++){
ma[i][j][0] = mi[i][j][0] = ac[i][j];
}
}
l[0]=1;
for(int i=1;i<=18;i++){
l[i]=l[i-1] * 2;
}
while(l[p1 + 1] <= n){
p1++;
}
for(int k = 1;k <= p1; k++){
for(int i = 1;i + (1 << k) - 1 <= a; i++){
for(int j = 1;j + (1 << k) - 1 <= b; j++){
ma[i][j][k]=max4(ma[i][j][k-1],ma[i + (1 << (k - 1))][j][k-1],
ma[i][j + (1 << (k - 1))][k-1],ma[i + (1 << (k - 1))][j + (1 << (k - 1))][k - 1]);
mi[i][j][k]=min4(mi[i][j][k - 1],mi[i + (1 << (k - 1))][j][k - 1],
mi[i][j + (1 << (k - 1))][k-1],mi[i + (1 << (k - 1))][j + (1 << (k - 1))][k - 1]);
}
}
}
// int k = 0;
// for(int i = 1;i <= n; ++i){
// if((1 << k) <= i) k++;
// que[i] = k - 1;
// }
int xiao = 2e9;
for(int i = 1;i + n - 1 <= a; i++){
for(int j = 1;j + n - 1<= b; j++){
//if(query(i,j) < xiao) xiao = query(i,j); ///!
xiao = min(xiao,query(i,j));
}
}
printf("%d\n" ,xiao);
return 0;
}
嗯对,这个也要努力记住,还有一道我不太会,暴搜的就得了30分,等讲过之后再整理吧。
482

被折叠的 条评论
为什么被折叠?



