2025-6-28-C++ 学习 模拟与高精度(8)

文章目录

  • 2025-6-28-C++ 学习 模拟与高精度(8)
  • P1591 阶乘数码
    • 题目描述
    • 输入格式
    • 输出格式
    • 输入输出样例 #1
      • 输入 #1
      • 输出 #1
    • 提交代码
  • P1249 最大乘积
    • 题目描述
    • 输入格式
    • 输出格式
    • 输入输出样例 #1
      • 输入 #1
      • 输出 #1
    • 提交代码
  • P1045 [NOIP 2003 普及组] 麦森数
    • 题目描述
    • 输入格式
    • 输出格式
    • 输入输出样例 #1
      • 输入 #1
      • 输出 #1
    • 说明/提示
    • 提交代码

2025-6-28-C++ 学习 模拟与高精度(8)

  模拟题,Come on ~~。

P1591 阶乘数码

题目描述

n ! n! n! 中某个数码出现的次数。

输入格式

第一行为 t ( t ≤ 10 ) t(t \leq 10) t(t10),表示数据组数。接下来 t t t 行,每行一个正整数 n ( n ≤ 1000 ) n(n \leq 1000) n(n1000) 和数码 a a a

输出格式

对于每组数据,输出一个整数,表示 n ! n! n! a a a 出现的次数。

输入输出样例 #1

输入 #1

2
5 2
7 0

输出 #1

1
2

提交代码

#include 
#include 
using namespace std;

// & 避免拷贝,提升效率
vector<int> multiply(vector<int>& a, int b)
{
    vector<int> res;
    int carry = 0;
    for(int k1 = 0; k1 < a.size() || carry; ++k1)
        {
            long long cur = carry;
            if(k1 < a.size()) cur += a[k1] * 1LL * b;
            res.push_back(cur % 10);
            carry = cur / 10;
        }
    
    // 移除前导零
    while(res.size() > 1 && res.back() == 0)
        {
            res.pop_back();
        }
    return res;
}


// 计算阶乘
vector<int> facterial(int n)
{
    vector<int> t = {1};

    for(int k1 = 2; k1 <= n; ++k1)
        {
            t = multiply(t, k1);
        }
    
    return t;
}

int main()
{
    int n;
    int a, b, ans;
    cin >> n;
    for(int k1 = 0; k1 < n; ++k1)
        {
            ans = 0;
            cin >> a >> b;
            vector<int> dig = facterial(a);
            for(auto cc : dig)
                {
                    if(cc == b) ans++;
                }
            cout << ans << endl;
        }

    return 0;
}

P1249 最大乘积

题目描述

一个正整数一般可以分为几个互不相同的自然数的和,如 3 = 1 + 2 3=1+2 3=1+2 4 = 1 + 3 4=1+3 4=1+3 5 = 1 + 4 = 2 + 3 5=1+4=2+3 5=1+4=2+3 6 = 1 + 5 = 2 + 4 6=1+5=2+4 6=1+5=2+4

现在你的任务是将指定的正整数 n n n 分解成若干个互不相同的自然数(也可以不分解,就是这个数字本身)的和,且使这些自然数的乘积最大。

输入格式

只一个正整数 n n n,( 3 ≤ n ≤ 10000 3 \leq n \leq 10000 3n10000)。

输出格式

第一行是分解方案,相邻的数之间用一个空格分开,并且按由小到大的顺序。

第二行是最大的乘积。

输入输出样例 #1

输入 #1

10

输出 #1

2 3 5
30

提交代码

#include 
#include 
using namespace std;

// 高精度乘法函数
void mul(vector<int>& result, int num) {
    int carry = 0;
    for (int i = 0; i < result.size() || carry; ++i) {
        if (i == result.size()) result.push_back(0);
        result[i] = result[i] * num + carry;
        carry = result[i] / 10;
        result[i] %= 10;
    }
}

int main() {
    int n;
    cin >> n;
    
    // 特例处理
    if (n == 3 || n == 4) {
        cout << n << endl;
        cout << n << endl;
        return 0;
    }
    
    vector<int> decomposition;
    int sum = 0;
    int i = 2;
    
    // 贪心分解
    while (sum < n) {
        decomposition.push_back(i);
        sum += i;
        i++;
    }
    
    // 调整分解方案
    if (sum > n) {
        int diff = sum - n;
        if (diff == 1) {
            decomposition[0] = 0; // 去掉最小的2
            decomposition.back() += 1; // 最后一个数加1
        } else {
            decomposition[diff - 2] = 0; // 去掉第diff个数
        }
    }
    
    // 输出分解方案
    for (int num : decomposition) {
        if (num != 0) cout << num << " ";
    }
    cout << endl;
    
    // 计算最大乘积
    vector<int> product(1, 1);
    for (int num : decomposition) {
        if (num != 0) mul(product, num);
    }
    
    // 输出最大乘积
    for (int i = product.size() - 1; i >= 0; --i) {
        cout << product[i];
    }
    cout << endl;
    
    return 0;
}

P1045 [NOIP 2003 普及组] 麦森数

题目描述

形如 2 P − 1 2^{P}-1 2P1 的素数称为麦森数,这时 P P P 一定也是个素数。但反过来不一定,即如果 P P P 是个素数, 2 P − 1 2^{P}-1 2P1 不一定也是素数。到 1998 年底,人们已找到了 37 个麦森数。最大的一个是 P = 3021377 P=3021377 P=3021377,它有 909526 位。麦森数有许多重要应用,它与完全数密切相关。

任务:输入 P ( 1000 < P < 3100000 ) P(1000P(1000<P<3100000),计算 2 P − 1 2^{P}-1 2P1 的位数和最后 500 500 500 位数字(用十进制高精度数表示)

输入格式

文件中只包含一个整数 P ( 1000 < P < 3100000 ) P(1000P(1000<P<3100000)

输出格式

第一行:十进制高精度数 2 P − 1 2^{P}-1 2P1 的位数。

2 ∼ 11 2\sim 11 211 行:十进制高精度数 2 P − 1 2^{P}-1 2P1 的最后 500 500 500 位数字。(每行输出 50 50 50 位,共输出 10 10 10 行,不足 500 500 500 位时高位补 0 0 0

不必验证 2 P − 1 2^{P}-1 2P1 P P P 是否为素数。

输入输出样例 #1

输入 #1

1279

输出 #1

386
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000104079321946643990819252403273640855
38615262247266704805319112350403608059673360298012
23944173232418484242161395428100779138356624832346
49081399066056773207629241295093892203457731833496
61583550472959420547689811211693677147548478866962
50138443826029173234888531116082853841658502825560
46662248318909188018470682222031405210266984354887
32958028878050869736186900714720710555703168729087

说明/提示

【题目来源】

NOIP 2003 普及组第四题

提交代码

#include 
#include 
#include 
#include 
#include 
using namespace std;

// 高精度乘法:将当前结果乘以2
void multiplyByTwo(vector<int>& digits) {
    int carry = 0;
    for (int i = 0; i < digits.size(); i++) {
        int temp = digits[i] * 2 + carry;
        digits[i] = temp % 10;
        carry = temp / 10;
    }
}

// 快速幂算法:计算2^P mod 10^500
vector<int> powMod(int P) {
    vector<int> result(500, 0);
    result[0] = 1; // 初始化为1 (2^0)
    
    vector<int> base(500, 0);
    base[0] = 2;   // 底数为2
    
    while (P > 0) {
        if (P % 2 == 1) {
            // 高精度乘法:result *= base
            vector<int> temp(500, 0);
            for (int i = 0; i < 500; i++) {
                int carry = 0;
                for (int j = 0; j < 500 - i; j++) {
                    int product = result[j] * base[i] + temp[i + j] + carry;
                    temp[i + j] = product % 10;
                    carry = product / 10;
                }
            }
            result = temp;
        }
        // 高精度乘法:base *= base
        vector<int> temp(500, 0);
        for (int i = 0; i < 500; i++) {
            int carry = 0;
            for (int j = 0; j < 500 - i; j++) {
                int product = base[j] * base[i] + temp[i + j] + carry;
                temp[i + j] = product % 10;
                carry = product / 10;
            }
        }
        base = temp;
        P /= 2;
    }
    return result;
}

int main() {
    int P;
    cin >> P;
    
    // 计算位数
    cout << (int)(P * log10(2)) + 1 << endl;
    
    // 快速幂计算2^P mod 10^500
    vector<int> digits = powMod(P);
    
    // 减去1 (2^P - 1)
    int idx = 0;
    while (digits[idx] == 0) {
        digits[idx] = 9;
        idx++;
    }
    digits[idx]--;
    
    // 输出结果,每行50个字符
    for (int i = 0; i < 10; i++) {
        for (int j = 0; j < 50; j++) {
            cout << digits[499 - (i * 50 + j)];
        }
        cout << endl;
    }
    
    return 0;
}

你可能感兴趣的:(2025-6-28-C++ 学习 模拟与高精度(8))