AcWing 888. 求组合数 IV

134 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第41天,点击查看活动详情

AcWing 888. 求组合数 IV

输入 a,b,求 Ca^b 的值。

注意结果可能很大,需要使用高精度计算。

输入格式

共一行,包含两个整数 a 和 b。

输出格式

共一行,输出 Ca^b 的值。

数据范围

1≤b≤a≤5000

输入样例:

5 3

输出样例:

10

思路

image.png

Cba(分解质因数)求分子分解每个p的次数cntmi(a!)为什么只+1而不是+k,因为a中pk低比如8!=1×2×3×4有2、4、6、8四个2,含2二次方所以只加二次方中的两个2含2三次方所以只加三次方中的一个2同理可类推到pk它的幂次中的前k−1个p同理可求分母的p的次数,答案==a×(a−1)×…×(a−b+1)b×(b−1)×…×1=a×(a−1)×…×(a−b+1)×(a−b)!b×(b−1)×…×1×(a−b)!=a!b!(a−b)!=pα11pα22…pαkk=[ap]下取整+[ap2]下取整+[ap3]下取整+…=p的倍数中∈[1,a]的个数+p2的倍数中∈[1,a]的个数+…阶项的次数已经被算过了比如p3既是p的倍数也是p2的倍数×5×6×7×8求其中2的个数,则1~8之间含2的一次有4、8,但4、8中2的一次方已经记过一次了,有8,但8中的一次、二次方都被记过一次了,在计算p1∼pk−1次数中都已经算过1次了∏ip分子次数和−分母次数和i

分解质因数法求组合数模板

当我们需要求出组合数的真实值,而非对某个数的余数时,分解质因数的方式比较好用:
1. 筛法求出范围内的所有质数
2. 通过 C(a, b) = a! / b! / (a - b)! 这个公式求出每个质因子的次数。 n! 中p的次数是 n / p + n / p^2 + n / p^3 + ...
3. 用高精度乘法将所有质因子相乘

int primes[N], cnt;     // 存储所有质数
int sum[N];     // 存储每个质数的次数
bool st[N];     // 存储每个数是否已被筛掉
void get_primes(int n)      // 线性筛法求素数
{
    for (int i = 2; i <= n; i ++ )
    {
        if (!st[i]) primes[cnt ++ ] = i;
        for (int j = 0; primes[j] <= n / i; j ++ )
        {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0) break;
        }
    }
}


int get(int n, int p)       // 求n!中的次数
{
    int res = 0;
    while (n)
    {
        res += n / p;
        n /= p;
    }
    return res;
}


vector<int> mul(vector<int> a, int b)       // 高精度乘低精度模板
{
    vector<int> c;
    int t = 0;
    for (int i = 0; i < a.size(); i ++ )
    {
        t += a[i] * b;
        c.push_back(t % 10);
        t /= 10;
    }

    while (t)
    {
        c.push_back(t % 10);
        t /= 10;
    }

    return c;
}

get_primes(a);  // 预处理范围内的所有质数

for (int i = 0; i < cnt; i ++ )     // 求每个质因数的次数
{
    int p = primes[i];
    sum[i] = get(a, p) - get(b, p) - get(a - b, p);
}

vector<int> res;
res.push_back(1);

for (int i = 0; i < cnt; i ++ )     // 用高精度乘法将所有质因子相乘
    for (int j = 0; j < sum[i]; j ++ )
        res = mul(res, primes[i]);

ac代码

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 5010;
int primes[N], cnt;
int sum[N];
bool st[N];
void get_primes(int n){
    for (int i = 2; i <= n; i ++ ){
        if (!st[i]) primes[cnt ++ ] = i;
        for (int j = 0; primes[j] <= n / i; j ++ ){
            st[primes[j] * i] = true;
            if (i % primes[j] == 0) break;
        }
    }
}
int get(int n, int p){
    int res = 0;
    while (n){
        res += n / p;
        n /= p;
    }
    return res;
}
vector<int> mul(vector<int> a, int b){
    vector<int> c;
    int t = 0;
    for (int i = 0; i < a.size(); i ++ ){
        t += a[i] * b;
        c.push_back(t % 10);
        t /= 10;
    }
    while (t){
        c.push_back(t % 10);
        t /= 10;
    }
    return c;
}
int main(){
    int a, b;
    cin >> a >> b;
    get_primes(a);
    for (int i = 0; i < cnt; i ++ ){
        int p = primes[i];
        sum[i] = get(a, p) - get(a - b, p) - get(b, p);
    }
    vector<int> res;
    res.push_back(1);
    for (int i = 0; i < cnt; i ++ )
        for (int j = 0; j < sum[i]; j ++ )
            res = mul(res, primes[i]);
    for (int i = res.size() - 1; i >= 0; i -- ) printf("%d", res[i]);
    puts("");
    return 0;
}