洛谷题单指南-数学基础问题-P1593 因子和

原题链接:https://www.luogu.com.cn/problem/P1593

题意解读:计算a^b的因子和。

解题思路:

1、如何计算因子和

我们知道,对于一个整数x,分解质因数后x = p1a1*p2a2*...*pnan

其所有因子和可以表示为(p10+p11+p12+...+p1a1)*(p20+p21+p22+...+p2a2)*...*(pn0+pn1+pn2+...+pnan)

这个式子拆开就是因子p1a*p2b*...*pnc的所有可能组合之和,a可以取0~a1,b可以取0~a2,c可以取0~an

接下来,对于一个数ab的因子和

将a分解质因数p1a1*p2a2*...*pnan, ab = p1a1*b * p2a2*b * ... * pnan*b

对于每一个质因数pi,计算pi0+pi1+pi2+...+piai*b, 再把结果相乘。

2、如何计算p0+p1+p2+...+px

可以采用分治法

设f(p, x)表示计算p0+p1+p2+...+px

当x == 0时,f(p, x) = 1

当x是奇数时,p0+p1+p2+...+px一共有偶数项,f(p, x) = f(p, x/2) + f(p, x / 2) * px/2+1

  例如x=5时,f(p, x/2) = p0+p1+p2, f(p, x/2) * px/2+1 = p3+...+p5, 所以f(p, x) = f(p, x/2) + f(p, x / 2) * px/2+1 = f(p, x/2) * (1 + px/2+1)

当x是偶数时,p0+p1+p2+...+px一共有奇数项,f(p, x) = f(p, x/2-1) + px/2+ f(p,x/2-1) * px/2+1

  例如x=6时,f(p, x/2-1) = p0+p1+p2表示左半部分, px/2=p3表示中间项,f(p,x/2-1) * px/2+1=p4+p5+p6表示右半部分,所以f(p, x) = f(p, x/2-1) + px/2+ f(p,x/2-1) * px/2+1 = f(p, x/2-1) * (1 + px/2+1 ) + px/2

递归即可实现上述过程。

//计算:(p^0 + p^1 + p^2 + ... + p^x 
LL f(LL p, LL x)
{
    if(x == 0) return 1;
    if(x % 2 == 1) return f(p, x / 2) * (1 + ksm(p, x / 2 + 1, MOD)) % MOD; //ksm(a, k, M)是计算a^k % M
    else return (f(p, x / 2 - 1) * (1 + ksm(p, x / 2 + 1, MOD)) % MOD + ksm(p, x / 2, MOD)) % MOD;
}

3、如何快速计算ak % M

在上述分治过程中,涉及计算px/2,px/2+1,如果采用普通的循环相乘求幂,时间复杂度过高,可以采用快速幂算法。

快速幂:ak % M

普通算法要把a乘k次,本题k在10^7范围,过大。

快速幂的思想是把k当做二进制,例如计算3^12,

12用二进制表示为1100,也就是2^3+2^2 = 8 + 4,所以3^12 = 3^(8+4) = 3^8 * 3^4

如何用程序模拟上述过程呢?

另初始x = 3,设答案res = 1

只需要从低到高遍历每一个二进制位,如果为1,则res = res * x ,再把x = x * x 

这样只需要遍历4次,而不是12次。快速幂的代码为(每一步加上了取模):

//计算a^k % p
int ksm(int a, int k, int M)
{
    int res = 1;
    while(k) 
    {
        if(k & 1) res = 1ll * res * a % M; //如果k的最二进制低位为1
        k = k >> 1; //k右移一位,考察下一个二进制位
        a = 1ll * a * a % M; //a每次翻倍
    }
}

100分代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

const int MOD = 9901;
long long a, b, ans = 1;

//快速幂:a^k % M
LL ksm(LL a, LL k, LL M)
{
    LL res = 1;
    while(k)
    {
        if(k & 1) res = res * a % M;
        k = k >> 1;
        a = a * a % M;
    }
    return res;
}

//计算:(p^0 + p^1 + p^2 + ... + p^x) % MOD
LL f(LL p, LL x)
{
    if(x == 0) return 1;
    if(x % 2 == 1) return f(p, x / 2) * (1 + ksm(p, x / 2 + 1, MOD)) % MOD;
    else return (f(p, x / 2 - 1) * (1 + ksm(p, x / 2 + 1, MOD)) % MOD + ksm(p, x / 2, MOD)) % MOD;
}

int main()
{
    cin >> a >> b;
    //分解质因数
    for(LL i = 2; i * i <= a; i++)
    {
        int cnt = 0;
        if(a % i == 0)
        {
            while(a % i == 0)
            {
                a /= i;
                cnt++;
            }
        }
        //cout << i << "^" << cnt * b << endl;
        //质因数i,指数cnt*b
        ans = ans * f(i, cnt * b) %  MOD;
    }
    if(a > 1) ans = ans * f(a, b) % MOD; //质因数a,指数b
    cout << ans;

    return 0;
}

 

posted @ 2024-04-17 11:26  五月江城  阅读(66)  评论(0编辑  收藏  举报