C++倍增法(练习题)

【倍增查找】

请在一个有序递增数组中(不存在相同元素),找出第一个>=x的值的位置,如果x在数组中不存在,请输出-1。

【输入】

第一行,一个整数n,代表数组元素个数(n <= 100)

第二行,n个整数,代表数组的n个递增元素(1<=数组元素值<=10^8)

第三行,一个整数x,代表要查找的数(0<=x<=10^8)

【输出】

x在数组中的位置,位置从1开始编号;没找到,输出-1。

【输入用例】

10

1 3 5 7 9 11 13 15 17 19

3

【输出用例】

2

cpp 复制代码
#include <iostream>
using namespace std;
int a[110];
int n;

// 在数组a[1~n]中倍增查找x的位置 
// 如果找到x,则返回x在数组a中的下标,否则返回-1
int search(int x)
{
	int L=1,p=1;
	while(p) {  //如果还能扩增范围(l)就继续
	    if(L+p <= n && a[L+p] <= x){
	        L += p;   //增加已知范围
	        p <<= 1;   //成倍增长,相当于p*=2
	    }else {
	        p >>= 1;  //缩小范围
    	}
	}
	return a[L] >= x ? L : -1;
}

int main()
{
	int x; // 要查找的值 
	cin >> n;
	for(int i=1; i<=n; i++){
		cin >> a[i];
	}
	cin >> x;
	cout << search(x);
	return 0;
}

/*
【输入用例2】
10
1 3 5 7 9 11 13 15 17 19
20
【输出用例2】
-1
【输入用例3】
10
1 3 5 7 9 11 13 15 17 19
-1
【输出用例3】
1
【输入用例4】
5
1 3 5 7 9
5
【输出用例4】
3
【输入用例5】
4
2 4 6 8
2
【输出用例5】
1
【输入用例6】
6
1 2 3 4 5 10
10
【输出用例6】
6
*/

斐波那契数列(倍增法)

【描述】关于斐波那契数列张三已经了解到不少知识,他发现除了其他方法能够实现精准输出斐波那契数列第几项外,利用倍增法似乎也能完成。请你帮助他设计一个倍增法输出斐波那契数列的程序。

【输入描述】输入一个数,表示需要输出第几项斐波那契数的值。

【输出描述】输出该项的斐波那契数值

【样例输入】

9

【样例输出】

F(9) = 34

cpp 复制代码
#include <iostream>
using namespace std;

// 快速倍增法计算斐波那契数
// 返回一个数对:{ F(n), F(n+1) }
// 使用 long long 以支持较大的数值
pair<long long, long long> fib_pair(int n) {
    if (n == 0) {
        // F(0) = 0, F(1) = 1
        return {0, 1};
    }
    
    // 递归计算 n/2 的结果
    auto p = fib_pair(n >> 1); // p = { F(k), F(k+1) } where k = n/2
    long long a = p.first;     // a = F(k)
    long long b = p.second;    // b = F(k+1)
    
    // 计算 F(2k) = F(k) * [2*F(k+1) - F(k)]
    long long c = a * (2 * b - a);
    
    // 计算 F(2k+1) = F(k)^2 + F(k+1)^2
    long long d = a * a + b * b;
    
    // 根据 n 的奇偶性返回结果
    if (n & 1) {
        // 如果 n 是奇数: n = 2k + 1
        // 返回 { F(2k+1), F(2k+2) }
        // F(2k+2) = F(2k+1) + F(2k)
        return {d, c + d};
    } else {
        // 如果 n 是偶数: n = 2k
        // 返回 { F(2k), F(2k+1) }
        return {c, d};
    }
}

// 包装函数:给定 n,返回 F(n)
long long fibonacci(int n) {
    return fib_pair(n).first;
}

int main() {
    int n;
    cin >> n;
    cout << "F(" << n << ") = " << fibonacci(n) << endl;
    
    return 0;
}
/*
【输入用例2】
0
【输出用例2】
F(0) = 0
【输入用例3】
15
【输出用例3】
F(15) = 610
【输入用例4】
25
【输出用例4】
F(25) = 75025
【输入用例5】
40
【输出用例5】
F(40) = 102334155
*/

模逆元

【描述】模逆元是模运算中的乘法逆元素,对于整数 a 和模数 m,若存在整数 b 满足:a * b≡ 1 mod m,则称 b 为 a 在模 m 下的逆元,记作 a^-1

模逆元存在条件:a 与 m 必须互质(即 gcd(a,m)=1)。现要求你编写程序使用快速幂算法计算模逆元。

【输入描述】输入为两个正整数,底数a和模数m

【输出描述】输出为底数a在模数m下的逆元

【样例输入1】2 3

【样例输出1】2 在模 3 下的逆元是: 2

【样例输入2】2 4

【样例输出2】逆元不存在(可能原因:a和m不互质或m非质数)

cpp 复制代码
#include <iostream>
using namespace std;

// 快速幂算法计算 (base^exp) % mod
long long fastPow(long long base, long long exp, long long mod)
{
    long long result = 1;
    base %= mod;  // 防止base过大
    
    while (exp > 0)
    {
        if (exp & 1) 
        {  // 如果当前二进制位为1
            result = (result * base) % mod;
        }
        base = (base * base) % mod;  // 底数平方
        exp >>= 1;  // 指数右移一位
    }
    return result;
}

int main() 
{
    long long a, m;
    cin >> a >> m;//输入底数a和模数m(用空格分隔)

    // 检查模数是否为质数(此处假设m是质数)
    // 实际应用中需要添加质数判断逻辑
    
    // 计算模逆元 a^(m-2) mod m
    long long inverse = fastPow(a, m-2, m);
    
    // 验证结果是否有效
    if (inverse * a % m == 1)
    {
        cout<< a << " 在模 "<< m << " 下的逆元是: " << inverse << endl;
    } 
    else 
    {
        cout << "逆元不存在(可能原因:a和m不互质或m非质数)" << endl;
    }
    return 0;
}

/*
【输入用例2】
3 7
【输出用例2】
3 在模 7 下的逆元是: 5
【输入用例3】
123456 1000003
【输出用例3】
123456 在模 1000003 下的逆元是: 414894
【输入用例4】
3 8
【输出用例4】
逆元不存在(可能原因:a和m不互质或m非质数)
【输入用例5】
4 2
【输出用例5】
逆元不存在(可能原因:a和m不互质或m非质数)
【输入用例6】
2 9
【输出用例6】
逆元不存在(可能原因:a和m不互质或m非质数)
*/

静态区间最大值查询

【描述】使用ST算法求解数组区间内的最大值为多少

【输入描述】首先一行输入一个数字n,接着第二行输入n个数组元素,第三行输入需要查询的区间数q,接下来的q行输入q个区间。

【输出描述】输出不同的区间中最大值

【样例输入】

5

3 3 3 3 3

3

1 5

2 4

3 3

【样例输出】

区间1,5的最大值为: 3

区间2,4的最大值为: 3

区间3,3的最大值为: 3

cpp 复制代码
#include <iostream>
using namespace std;

const int MAX_N = 1010;
int st[MAX_N][20];  // st[i][j]表示从i开始长度为2^j的区间最大值
int arr[MAX_N];

// 构建ST表
void buildST(int n) 
{
    // 初始化长度为1的区间
    for (int i = 1; i <= n; i++) 
    {
        st[i][0] = arr[i];
    }
    
    // 计算长度大于1的区间
    for (int j = 1; (1 << j) <= n; j++) 
    {
        for (int i = 1; i + (1 << j) - 1 <= n; i++) 
        {
            st[i][j] = max(st[i][j-1], st[i + (1 << (j-1))][j-1]);
        }
    }
}

// 查询区间[l,r]的最大值
int queryRMQ(int l, int r)
{
    int len = r - l + 1;
    int k = 0;
    while ((1 << (k+1)) <= len) k++;
    
    // 查询区间[l, l+2^k-1]和[r-2^k+1, r]的最大值
    return max(st[l][k], st[r - (1 << k) + 1][k]);
}

int main()
{
    int n, q;
    cin >> n;//输入数组大小n
    
    //输入数组元素
    for (int i = 1; i <= n; i++)
    {
        cin >> arr[i];
    }
    
    buildST(n);
    
    //输入查询次数q
    cin >> q;
    while (q--)
    {
        int l, r;
        cin >> l >> r;
        cout << "区间["<< l << ","<< r << "]的最大值为: " << queryRMQ(l, r) << endl;
    }
    return 0;
}

/*
【输入用例2】
1
5
1
1 1
【输出用例2】
区间[1,1]的最大值为: 5
【输入用例3】
6
1 2 3 4 5 6
2
1 6
3 5
【输出用例3】
区间[1,6]的最大值为: 6
区间[3,5]的最大值为: 5
【输入用例4】
5
9 7 5 3 1
2
1 5
2 4
【输出用例4】
区间[1,5]的最大值为: 9
区间[2,4]的最大值为: 7
【输入用例5】
8
3 9 2 7 5 8 1 6
3
1 8
4 6
2 5
【输出用例5】
区间[1,8]的最大值为: 9
区间[4,6]的最大值为: 8
区间[2,5]的最大值为: 9
【输入用例6】
7
-3 0 15 -8 25 7 -1
3
1 7
3 6
5 5
【输出用例6】
区间[1,7]的最大值为: 25
区间[3,6]的最大值为: 25
区间[5,5]的最大值为: 25
*/

区间GCD查询

【描述】使用ST表来预处理数组,快速查询任意区间的最大公约数(GCD)

【输入描述】首先一行输入一个数字n,接着第二行输入n个数组元素,第三行输入需要查询的区间数q,接下来的q行输入q个区间。

【输出描述】输出q个区间内所有元素的最大公约数

【样例输入】

6

2 4 5 7 11 13

2

1 2

3 4

【样例输出】

区间1,2的GCD为: 2

区间3,4的GCD为: 1

cpp 复制代码
#include <iostream>
using namespace std;

const int MAX_N = 1010;
int st[MAX_N][20];  // st[i][j]表示从i开始长度为2^j的区间的GCD值
int arr[MAX_N];

// 计算两个数的最大公约数
int gcd(int a, int b) {
    while (b) {
        int temp = b;
        b = a % b;
        a = temp;
    }
    return a;
}

// 构建ST表
void buildST(int n) {
    // 初始化长度为1的区间
    for (int i = 1; i <= n; i++) {
        st[i][0] = arr[i];
    }
    
    // 计算长度大于1的区间
    for (int j = 1; (1 << j) <= n; j++) {
        for (int i = 1; i + (1 << j) - 1 <= n; i++) {
            st[i][j] = gcd(st[i][j-1], st[i + (1 << (j-1))][j-1]);
        }
    }
}

// 查询区间[l,r]的最大公约数
int queryGCD(int l, int r) {
    int len = r - l + 1;
    int k = 0;
    while ((1 << (k+1)) <= len) k++;
    
    // 查询区间[l, l+2^k-1]和[r-2^k+1, r]的最大公约数
    return gcd(st[l][k], st[r - (1 << k) + 1][k]);
}

int main() {
    int n, q;
    //输入数组大小n
    cin >> n;
    
    //输入数组元素
    for (int i = 1; i <= n; i++) {
        cin >> arr[i];
    }
    
    buildST(n);
    
    //输入查询次数q
    cin >> q;
    while (q--) {
        int l, r;
        cin >> l >> r;
        cout << "区间["<< l << ","<< r << "]的GCD为: " << queryGCD(l, r) << endl;
    }
    
    return 0;
}

/*
【输入用例2】
1
5
1
1 1
【输出用例2】
区间[1,1]的GCD为: 5
【输入用例3】
5
0 0 0 0 0
3
1 5
2 3
5 5
【输出用例3】
区间[1,5]的GCD为: 0
区间[2,3]的GCD为: 0
区间[5,5]的GCD为: 0
【输入用例4】
7
0 6 0 9 0 12 0
3
1 7
2 5
4 6
【输出用例4】
区间[1,7]的GCD为: 3
区间[2,5]的GCD为: 3
区间[4,6]的GCD为: 3
【输入用例5】
4
123456 234567 345678 456789
2
1 4
2 3
【输出用例5】
区间[1,4]的GCD为: 3
区间[2,3]的GCD为: 3
【输入用例6】
8
4 8 12 16 20 24 28 32
3
1 8
2 6
5 7
【输出用例6】
区间[1,8]的GCD为: 4
区间[2,6]的GCD为: 4
区间[5,7]的GCD为: 4
*/
相关推荐
凡人叶枫2 小时前
Effective C++ 条款23:宁以 non-member、non-friend 替换 member 函数
linux·开发语言·c++·嵌入式开发
C语言小火车2 小时前
什么时候用智能指针?什么时候用裸指针?
c语言·c++·学习·指针
玖玥拾3 小时前
C/C++ 基础笔记(十二)友元、运算符重载
c语言·c++·运算符重载·友元
智者知已应修善业3 小时前
【51单片机8位数码管同时倒计时从9999】2024-1-25
c++·经验分享·笔记·算法·51单片机
洛水水3 小时前
【力扣100题】86.柱状图中最大的矩形
算法·leetcode·职场和发展
渡之3 小时前
GRiM-Net 深度解析 | 无人机 GNSS 拒止场景下两阶段跨视角视觉定位框架
深度学习·算法·动态规划·无人机
测试仪器廖生135902563853 小时前
罗德与施瓦茨 FSP13频谱分析仪FSP30
网络·人工智能·算法
happymaker06263 小时前
LeetCodeHot100——560.和为K的子数组
算法
dtq04244 小时前
C语言刷题数组5,6(求平均值,求最大值)
c语言·数据结构·算法