leetcode301周赛记录

该博客介绍了如何利用质因数分解和组合计数解决理想数组数目问题。作者首先提出通过枚举子数组最后一个数字并累加的方法,然后关键在于分解质因数并分配到各个位置。文章中给出了一种模板,通过组合数学的隔板法计算不同质因数的分配方式,并实现了一个高效的组合数计算类。最后,展示了如何根据质因数分布计算理想数组的总数,同时提供了代码实现。
摘要由CSDN通过智能技术生成

统计理想数组的数目(GOOD)

在这里插入图片描述
在这里插入图片描述

  • 划分解空间:枚举子数组最后一个数字然后累加
  • 最关键的步骤:利用分解质因数枚举后一个数相对前一个数的倍率。

具体地,对最后一个数字每个质因子j,设有i个质因子j,将其分配到n个位置。采用隔板法将i个质因子j分成n份,两个隔板如无质因子则认为对应的盒子中数字与前一个数字相同。共n-1个隔板,i个数字,则对每个质因子j划分种类数为 C n − 1 + i n − 1 C_{n-1+i}^{n-1} Cn1+in1。对某一质因子j的分配方法,对另一质因子 j , j^, j,都可另生成 C n − 1 + i , n − 1 C_{n-1+i^,}^{n-1} Cn1+i,n1种全新的方法,其中 i , i^, i,是质因子 j , j^, j,的次数,以此类推。

const int MOD = 1e9 + 7;
class Comb {
    vector<int> Facs, Invs;
    void expand(size_t n) {
        while(Facs.size() < n + 1) Facs.push_back(1ll * Facs.back() * Facs.size() % MOD);
        if(Invs.size() < n + 1) { // 线性求阶乘的逆元
            Invs.resize(n + 1, 0);
            Invs.back() = 1;
            for(int a = Facs[n], p = MOD - 2; p; p >>= 1, a = 1ll * a * a % MOD)
                if(p & 1) Invs.back() = 1ll * Invs.back() * a % MOD; // 快速乘求 n! 的逆元
            for(int j = n-1; !Invs[j]; --j) Invs[j] = 1ll * Invs[j+1] * (j + 1) % MOD;
        }
    }
public:
    Comb() : Facs({1}), Invs({1}) {}
    Comb(int n) : Facs({1}), Invs({1}) { expand(n); }
    int operator() (int n, int k) {
        if(k > n) return 0;
        expand(n);
        return (1ll * Facs[n] * Invs[n-k] % MOD) * Invs[k] % MOD; 
    }
};

Comb comb;
typedef long long ll;
class Solution {
public:
    int idealArrays(int n, int maxValue) {
        if(maxValue == 1) return 1;
        bool isp[maxValue + 1];
        isp[1] = false; isp[2] = true;
        vector<int> p; p.push_back(2);
        const int mod = 1e9+7;
        for(int i = 3;i<=maxValue;i++)
        {
            isp[i]=true;
            for(int j = 2;j * j <= i;j++) if(i%j==0) {isp[i]=false;break;}
            if(isp[i]) p.push_back(i);
        }
        int ans = 1;
        for(int last = 2;last <= maxValue;last++)
        {
            int temp = last;
            if(isp[temp]) ans = (ans + n) % mod;
            else   //分解质因数
            {
                int cur = 0;
                int t = 1;
                while(temp > 1)
                {
                    int count = 0;   //当前质因数的个数
                    while(temp > 1 && temp % p[cur] == 0) {temp /= p[cur]; count++;} 
                    if(count > 0)    //如果当前质因数个数大于0
                    {
                        t = ((ll)1 * t * comb(n + count - 1,count)) % mod;
                    } 
                    cur++;
                }
                ans = ( ans + t ) % mod;
            }
        }
        return ans;
    }
};

上述代码求组合数地模板非常好用,值得珍藏。
反思:没有想到可以将质因数分配到每个位置上,即枚举倍率来计数,只想到对每个长度,互相不同的数的种类数进行计数。并且一开始就只想使用开头固定的数字划分解空间了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值