复习dddddddd

1.

思路:用队列先进先出的特性

cpp 复制代码
#include <iostream>
#include <vector>
#include <stack>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <climits>
#include <cstdlib>
#include <cmath>
#include <unordered_set>
#include <unordered_map>
#include <queue>
#include <list>
#include <map>
#include <set>

using namespace std;


int main() {
    int n; cin >> n;
    queue<pair<int, int>>arr; // 下标,值
    n = pow(2, n);
    for (int i = 1; i <= n; i++) {
        int temp;
        cin >> temp;
        arr.push({ i,temp });
    }

    while (arr.size() > 2) {
        auto l = arr.front();
        arr.pop();
        auto r = arr.front();
        arr.pop();
        if (l.second > r.second)arr.push({ l.first,l.second });
        else arr.push({ r.first,r.second });
    }
    auto l = arr.front();
    arr.pop();
    auto r = arr.front();
    if (l.second > r.second)cout << r.first;
    else cout << l.first;

    return 0;
}

2.

思路:二叉树的数组定义来写

cpp 复制代码
#include <iostream>
#include <vector>
#include <stack>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <climits>
#include <cstdlib>
#include <cmath>
#include <unordered_set>
#include <unordered_map>
#include <queue>
#include <list>
#include <map>
#include <set>

using namespace std;

struct Node {
    int l, r;
}s[1000001];
int tt = -1;

void dfs(int n,int coun) {
    if (n==0)return;
    tt = max(tt, coun);
    dfs(s[n].l, coun + 1);
    dfs(s[n].r, coun + 1);
}

int main() {
    int n; cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> s[i].l >> s[i].r;
    dfs(1,1);
    cout << tt << endl;
    return 0;
}

3.

思路: 用递归的方法来分出左右子树,以及以其为子节点为节点的左右子树,直到叶子节点

cpp 复制代码
#include <iostream>
#include <vector>
#include <stack>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <climits>
#include <cstdlib>
#include <cmath>
#include <unordered_set>
#include <unordered_map>
#include <queue>
#include <list>
#include <map>
#include <set>

using namespace std;

void func(string& s1, string& s2) {
    char root = s1[0];
    int l = s2.find(root), r = s1.size() - l - 1;
    if (l) {
        string str1 = s1.substr(1, l), str2 = s2.substr(0, l);
        func(str1, str2);
    }
    if (r) {
        string str1 = s1.substr(l + 1), str2 = s2.substr(l + 1);
        func(str1, str2);
    }
    cout << root;

}

int main() {
    string s1, s2;
    cin >> s2 >> s1;
    func(s1, s2);
    return 0;
}

4.

思路:广搜探索所有的组成方式

cpp 复制代码
#include <iostream>
#include <queue>
#include <unordered_set>
#include <unordered_map>
#include <string>
#include <vector>
using namespace std;

 
typedef pair<string, string> Rule;

 
int bfs(const string& A, const string& B, const vector<Rule>& rules) {
    if (A == B) return 0;  

    queue<pair<string, int>> q; 
    q.push({A, 0});

    unordered_set<string> visited;  
    visited.insert(A);

    while (!q.empty()) {
        auto current = q.front();
        q.pop();
        string currentStr = current.first;
        int steps = current.second;

        
        if (currentStr == B) {
            return steps;
        }

     
        if (steps >= 10) {
            continue;
        }

     
        for (const auto& rule : rules) {
            const string& from = rule.first;
            const string& to = rule.second;

            size_t pos = currentStr.find(from);
            while (pos != string::npos) {
   
                string newStr = currentStr;
                newStr.replace(pos, from.length(), to);

      
                if (visited.find(newStr) == visited.end()) {
                    visited.insert(newStr);
                    q.push({newStr, steps + 1});
                }
 
                pos = currentStr.find(from, pos + 1);
            }
        }
    }

    return -1; 
}

int main() {
    string A, B;
    cin >> A >> B;

    vector<Rule> rules;
    string a, b;
    while (cin >> a >> b) {
        rules.push_back({a, b});
    }

    int result = bfs(A, B, rules);

    if (result != -1) {
        cout << result << endl;
    } else {
        cout << "NO ANSWER!" << endl;
    }

    return 0;
}

5.算阶

思路:二进制枚举每个位置上能否放1,经过整个流程后还是1,则则这个位置是1,同时整个的值也要小于m才是ans

cpp 复制代码
#include <iostream>
#include <vector>
#include <stack>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <climits>
#include <cstdlib>
#include <cmath>
#include <unordered_set>
#include <unordered_map>
#include <queue>
#include <list>
#include <map>
#include <set>

using namespace std;

pair<string, int> operations[100005];
int n, m;

int calc(int bit, int now) {
    for (int i = 1; i <= n; i++) {
        int x = operations[i].second >> bit & 1;
        if (operations[i].first == "AND") now &= x;
        else if (operations[i].first == "OR") now |= x;
        else now ^= x;
    }
    return now;
}

int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        char str[5]; int num;
        scanf("%s%d", str, &num);
        operations[i] = make_pair(str, num);
    }

    int val = 0, ans = 0;
    for (int bit = 29; bit >= 0; bit--) {
        int res0 = calc(bit, 0);
        int res1 = calc(bit, 1);
        if ((val + (1 << bit)) <= m && res0 < res1) {
            val += 1 << bit; ans += res1 << bit;
        }
        else {
            ans += res0 << bit;
        }
    }

    cout << ans << endl;
    return 0;
}

6.

思路:

解题思路

  1. 唯一分解定理

    将 a 分解为素数的乘积:

    a=p1k1⋅p2k2⋅⋯⋅pnkn

    则 ab 的因子和为:
    σ(ab)=(1+p1+p12+⋯+p1k1⋅b)⋅(1+p2+p22+⋯+p2k2⋅b)⋅⋯⋅(1+pn+pn2+⋯+pnkn⋅b)

  2. 等比数列求和

    对于每个素数 pi​,其对应的等比数列和为:

    Si=1+pi+pi2+⋯+piki⋅b=pi−1piki⋅b+1−1

  3. 模运算性质

    由于结果需要对 9901 取模,我们需要在计算过程中对每一步结果取模,避免溢出。

  4. 快速幂算法

    计算 piki​⋅b+1​ 时,使用快速幂算法提高效率。

  5. 逆元计算

    在计算等比数列和时,分母 pi​−1 可能不为 1,因此需要计算 pi​−1 在模 9901 下的逆元。

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

const int MOD = 9901;

// 快速幂算法
long long fastPow(long long base, long long exp, long long mod) {
    long long result = 1;
    while (exp > 0) {
        if (exp & 1) {
            result = (result * base) % mod;
        }
        base = (base * base) % mod;
        exp >>= 1;
    }
    return result;
}

// 扩展欧几里得算法求逆元
int extendedEuclidean(int a, int m, int& x, int& y) {
    if (m == 0) {
        x = 1;
        y = 0;
        return a;
    }
    int x1, y1;
    int gcd = extendedEuclidean(m, a % m, x1, y1);
    x = y1;
    y = x1 - (a / m) * y1;
    return gcd;
}

// 计算 a 在模 m 下的逆元
int modularInverse(int a, int m) {
    int x, y;
    int gcd = extendedEuclidean(a, m, x, y);
    if (gcd != 1) {
        return -1; // 逆元不存在
    } else {
        return (x % m + m) % m; // 确保结果为正
    }
}

// 分解质因数
vector<pair<int, int>> primeFactorization(int n) {
    vector<pair<int, int>> factors;
    for (int i = 2; i * i <= n; i++) {
        if (n % i == 0) {
            int count = 0;
            while (n % i == 0) {
                n /= i;
                count++;
            }
            factors.push_back({i, count});
        }
    }
    if (n > 1) {
        factors.push_back({n, 1});
    }
    return factors;
}

// 计算 a^b 的因子和对 MOD 取模
int sumOfDivisors(int a, int b) {
    if (a == 0) return 0; // 0^b 的因子和为 0
    if (b == 0) return 1; // a^0 的因子和为 1

    // 分解质因数
    vector<pair<int, int>> factors = primeFactorization(a);

    long long result = 1;
    for (const auto& factor : factors) {
        int p = factor.first;
        int k = factor.second;

        // 计算等比数列和 S = (p^(k*b + 1) - 1) / (p - 1)
        long long numerator = (fastPow(p, k * b + 1, MOD) - 1 + MOD) % MOD;
        long long denominator = (p - 1) % MOD;

        // 如果 p == 1,等比数列和为 k * b + 1
        if (p == 1) {
            result = (result * (k * b + 1)) % MOD;
            continue;
        }

        // 计算分母的逆元
        int inv = modularInverse(denominator, MOD);
        if (inv == -1) {
            // 如果分母为 0,等比数列和为 k * b + 1
            result = (result * (k * b + 1)) % MOD;
        } else {
            // 计算 S 并对 MOD 取模
            long long S = (numerator * inv) % MOD;
            result = (result * S) % MOD;
        }
    }

    return result;
}

int main() {
    int a, b;
    cin >> a >> b;
    cout << sumOfDivisors(a, b) << endl;
    return 0;
}

7.逆元

逆元是数论中的一个重要概念,尤其在模运算中广泛应用。它的核心思想是解决模意义下的"除法"问题。因为模运算中除法并不直接定义,而是通过乘法逆元来实现。


1. 逆元的定义

给定一个整数 a 和一个模数 m,如果存在一个整数 x,使得:

a⋅x≡1(modm)

则称 x 是 a 在模 m 下的乘法逆元,记作 a−1。


2. 将模等式转化为常规等式

模等式 a⋅x≡1(modm) 可以转化为常规等式:

a⋅x+m⋅k=1

其中 k 是某个整数。这个等式表明,a⋅x 与 1 的差是 m 的倍数。


3. 逆元的存在条件

a 在模 m 下的逆元存在的充要条件是 a 和 m 互质,即:

gcd(a,m)=1

如果 a 和 m 不互质,则 a 在模 m 下没有逆元。


4. 逆元的计算方法

(1) 扩展欧几里得算法

扩展欧几里得算法可以求解方程 a⋅x+m⋅k=1。如果 gcd(a,m)=1,则 x 就是 a 在模 m 下的逆元。

步骤:

  1. 使用扩展欧几里得算法求解 gcd(a,m) 以及 x 和 k。
  2. 如果 gcd(a,m)=1,则 x 是 a 的逆元。
  3. 将 x 调整为正数(通过取模)。
cpp 复制代码
#include <iostream>
using namespace std;

// 扩展欧几里得算法
int extendedEuclidean(int a, int m, int& x, int& y) {
    if (m == 0) {
        x = 1;
        y = 0;
        return a;
    }
    int x1, y1;
    int gcd = extendedEuclidean(m, a % m, x1, y1);
    x = y1;
    y = x1 - (a / m) * y1;
    return gcd;
}

// 计算 a 在模 m 下的逆元
int modularInverse(int a, int m) {
    int x, y;
    int gcd = extendedEuclidean(a, m, x, y);
    if (gcd != 1) {
        return -1; // 逆元不存在
    } else {
        return (x % m + m) % m; // 确保结果为正
    }
}

int main() {
    int a, m;
    cout << "请输入 a 和 m: ";
    cin >> a >> m;

    int inv = modularInverse(a, m);
    if (inv == -1) {
        cout << a << " 在模 " << m << " 下没有逆元。" << endl;
    } else {
        cout << a << " 在模 " << m << " 下的逆元是: " << inv << endl;
    }

    return 0;
}
(2) 费马小定理

如果模数 m 是素数,且 a 不是 m 的倍数,则根据费马小定理:

a^m−1≡1(modm)

因此,a 的逆元为:

a−1≡a^m−2(modm)

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

// 快速幂算法
long long fastPow(long long a, long long b, long long mod) {
    long long result = 1;
    while (b > 0) {
        if (b & 1) {
            result = (result * a) % mod;
        }
        a = (a * a) % mod;
        b >>= 1;
    }
    return result;
}

// 计算 a 在模 m 下的逆元(费马小定理)
int modularInverse(int a, int m) {
    return fastPow(a, m - 2, m);
}

int main() {
    int a, m;
    cout << "请输入 a 和 m: ";
    cin >> a >> m;

    if (m <= 1 || a % m == 0) {
        cout << a << " 在模 " << m << " 下没有逆元。" << endl;
    } else {
        int inv = modularInverse(a, m);
        cout << a << " 在模 " << m << " 下的逆元是: " << inv << endl;
    }

    return 0;
}

逆元运用

5. 逆元的应用

  1. 模意义下的除法
    • 在模运算中,a/b 等价于 a⋅b−1(modm)。
  2. 线性同余方程
    • 解方程 a⋅x≡b(modm) 时,需要用到 a 的逆元。
  3. 组合数学
    • 计算组合数 C(n,k) 时,通常需要用到模意义下的除法。
  4. 密码学
    • RSA 加密算法中,逆元用于计算私钥。
相关推荐
curemoon7 分钟前
理解都远正态分布中指数项的精度矩阵(协方差逆矩阵)
人工智能·算法·矩阵
柃歌16 分钟前
【UCB CS 61B SP24】Lecture 7 - Lists 4: Arrays and Lists学习笔记
java·数据结构·笔记·学习·算法
JANGHIGH19 分钟前
c++ std::list使用笔记
c++·笔记·list
柃歌25 分钟前
【UCB CS 61B SP24】Lecture 4 - Lists 2: SLLists学习笔记
java·数据结构·笔记·学习·算法
画个逗号给明天"26 分钟前
C++STL容器之list
开发语言·c++
干炒 牛河31 分钟前
数据结构:双链表list
数据结构·list
SKYDROID云卓小助手2 小时前
无人设备遥控器之如何分享数传篇
网络·人工智能·算法·计算机视觉·电脑
Lqingyyyy2 小时前
P2865 [USACO06NOV] Roadblocks G 与最短路的路径可重复的严格次短路
开发语言·c++·算法
C语言小火车2 小时前
深入解析C++26 Execution Domain:设计原理与实战应用
java·开发语言·c++·异构计算调度·c++26执行模型·domain定制
醉城夜风~2 小时前
[数据结构]顺序表详解
数据结构