快速幂的应用:Sumdiv

该博客详细解析了POJ 1845题目的解题思路,主要涉及质因数分解和快速幂运算。作者首先介绍了如何求解一个数的约数和,通过将数分解为质因数的乘积形式,然后利用等比数列公式计算每个质因数的贡献。接着,针对A^B的形式,讨论了当质因数减1与模数互质时使用逆元的概念,以及不互质时的处理方法。最后,提供了C++代码实现,展示了如何在实际编程中应用这些理论知识解决数学问题。
摘要由CSDN通过智能技术生成

题目链接:http://poj.org/problem?id=1845

题目:

分析:

此题首先,求约数和,所以可以想到求约数和的方法(p1^0 + p1 ^ 1 + p1 ^ 2..... + p1 ^ x1) * (p2^0 + p2 ^ 1 + p2 ^ 2..... + p2 ^ x2) ....

所以首先将A的质因数 以及 其指数求解出来。

p1 ^ x1 + p2 ^ x2 + p3 ^ x3.....

然后它求的是A ^ B, 所以实际上是 p1 ^ (B * x1) * p2 ^(B * x2) .....

所以求约数和变为了  (p1^0 + p1 ^ 1 + p1 ^ 2..... + p1 ^ (x1 *B)) * (p2^0 + p2 ^ 1 + p2 ^ 2..... + p2 ^( x2*B ) )....

而这个之中乘法的每一项都可以看作是一个等比数列。直接按照等比数列的公式求出每一项即可。

最后每一项都得到这么一个公式

 其中 p1 ^ (B  *c + 1)则可以直接使用快速幂的方法进行求解。

而p1 - 1的情况,

由于我们mod 的值为9901,是一个质数, 所以 / (p1 - 1)可以使用求逆元的方法得到结果。

但是逆元的话,前提条件是 p1 -1 与 mod的值互质。  而mod为质数,只有p1 - 1 不是 mod 的倍数的时候,才能用快速幂求解逆元(因为mod 也为质数)。

而如果p1 - 1 与 mod 不互质的话呢?

这个时候请看原先的公式,

(p1 ^ x0 + p1 ^ x1 + p2 ^ x2....) % (mo0d),

那么结果实际上就是 (1 + 1 +  1 + .... 1)% mod   也就是 (B * c + 1) % mod.

所以,此题,求出质因数和指数后,准备求乘积是,先判断p - 1 是否与 mod 互质, 按照两种情况分别来求即可。 

代码实现:

# include <iostream>
# include <cmath>
using namespace std;

const int mod = 9901;


int qmi(int a , long long b , int mod)  // 不会爆longlong所以不需要使用快速乘
{
    int res = 1;
    while(b)
    {
        if(b & 1)
        {
            res = (long long)res * a % mod;
        }
        b >>= 1;
        a = (long long)a * a % mod;
    }
    return res;
}

int main()
{
    int a,b;
    scanf("%d %d",&a,&b);

    int ans = 1; // 答案

    // 筛出a的质因数出来
    for(int i = 2 ; i <= a / i ; i++)
    {
        if(a % i == 0)
        {
            int res = 0;
            while(a % i == 0)
            {
                res ++;
                a /= i;
            }
            // 质数为i i ,
            // 指数为 res * b , 但是要注意 res * b 可能会爆int
            long long temp = (long long)res * b;
            if(( i - 1 ) % mod == 0)
            {
                ans = ( (temp + 1) )  % mod * (long long)ans % mod ; // 防止temp + 1 很大,乘以一个ans后爆long long
            }
            else
            {
                // 先求 i - 1的逆元
                int temp1 = qmi(i - 1,  mod - 2 , mod);

                // 再求 q ^ (b * c1 + 1)次方
                int temp2 = ( qmi(i,temp + 1,mod) - 1 + mod) % mod;
                ans = ( ( (long long)ans * temp2 % mod) * (long long)temp1) % mod;
            }
        }
    }
    if(a > 1)
    {
        // a为质数
        // b为指数
            long long temp = (long long)1 * b;
            if(( a - 1 ) % mod == 0)
            {
                ans = ( (temp + 1) )  % mod * (long long)ans % mod ; // 防止temp + 1 很大,乘以一个ans后爆long long
            }
            else
            {
                // 先求 a - 1的逆元
                int temp1 = qmi(a - 1,  mod - 2 , mod);

                // 再求 a ^ (b  + 1)次方
                int temp2 = ( qmi(a,temp + 1,mod) - 1 + mod) % mod;
                ans = ( ( (long long)ans * temp2 % mod) * (long long)temp1) % mod;
            }
    }
    printf("%d\n",ans);


    return 0;
}
这道题目是求一个表达式的结果,表达式中包含了欧拉函数和向下取整操作。需要注意的是,最后结果需要对一个给定的mod取模。 首先,我们可以把这个表达式分成两部分来计算。第一部分是计算φ(i)的前缀和,第二部分是计算⌊n/i⌋的前缀和。 对于第一部分,我们可以使用线性筛法来计算φ(i)的前缀和。具体步骤如下: 1. 初始化一个数组phi,大小为k+1,用来保存欧拉函数的值。 2. 初始化一个数组prime,用来保存质数。 3. 初始化一个数组isPrime,大小为k+1,用来标记是否是质数。 4. 初始化一个数组sumPhi,大小为k+1,用来保存φ(i)的前缀和。 5. 遍历2到k的每个数i,如果isPrime[i]为true,则将i加入到prime数组中,并且令phi[i] = i-1。 否则,找到i的最小质因数p,令phi[i] = phi[i/p] * p / (p-1)。 6. 遍历prime数组中的每个质数p,更新phi数组中所有p的倍数的值,令phi[i] = phi[i] * p / (p-1)。 7. 计算sumPhi数组的前缀和,即sumPhi[i] = sumPhi[i-1] + phi[i]。 对于第二部分,我们可以使用容斥原理来计算⌊n/i⌋的前缀和。具体步骤如下: 1. 初始化一个数组sumDiv,大小为k+1,用来保存⌊n/i⌋的前缀和。 2. 遍历1到k的每个数i,计算sumDiv[i] = sumDiv[i-1] + ⌊n/i⌋。 3. 使用容斥原理,减去所有的sumDiv[i] * φ(i),其中i为k的因子。 最后,将第一部分和第二部分的结果相乘,并对mod取模,即可得到最终结果。 以上就是求解这道题目的思路和步骤。希望对你有帮助!如果有任何疑问,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值