POJ1845 Sumdiv

算法竞赛 数学 数学-质数
编辑文章

题意

求 $A^{B}$ 的约数和。对 $9901$ 取模。

其中 $A,B\le 5\times 10^{7}$ 。

题解

将 $A$ 分解:

$$A=\prod_{i=1}^n p_i^{a_i}$$

那么约数和为:

$$\prod_{i=1}^n \sum_{j=0}^{a_i\times B} {p_i}^j $$

所以可以先预处理出 $\le \sqrt{A}$ 的质数,然后对 $A$ 进行分解。

剩下的东西就是对很多等比数列求和,然后相乘了。求和直接用公式:

$$S_n=\dfrac{a_1-a_n\times q}{1-q}$$

很显然需要对除法取模,可以用取模的某个性质。我也不知道这个叫什么,反正是有这个性质。

对于

$$\dfrac{x}{y} \ mod \ p$$

可以化为

$$\dfrac{x \ mod \ (y\times p)}{y} \tag{1}$$

然后就可以求了。快速幂中的模数也需要改成 $y\times p$ 这种形式。

我就很愉快的这么做了,然后很愉快的得了 $95$ 分。

然后发现当 $A$ 是质数时,$1-q$ 就会很大,这就意味着转化为 $(1)$ 式中 $y\times p$ 会爆 int ,然后过程中就会爆 long long,所以我就用 __int128 水过了。

#include<bits/stdc++.h>
#define ll __int128
#define ha 9901

using namespace std;

inline ll read()
{
    char ch=getchar();
    ll f=1,x=0;
    while (ch<'0' || ch>'9')
    {
        if (ch=='-') f=-1;
        ch=getchar();
    }
    while (ch>='0' && ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return f*x;
}

bool ss[7100];
ll zs[2005],cnt,A,B,c[2005];

inline void get_prime()
{
    memset(ss,1,sizeof(ss));
    ss[0]=ss[1]=0;
    for (ll i=2;i*i<=A;i++)
    {
        if (ss[i]) zs[++cnt]=i;
        for (ll j=1;j<=cnt && zs[j]*i*zs[j]*i<=A;j++)
        {
            ss[zs[j]*i]=0;
            if (i%zs[j]==0) break;
        }
    }
}

inline ll get_c()
{
    ll n=A;
    for (ll i=1;i<=cnt;i++)
    {
        while (n%zs[i]==0)
        {
            n/=zs[i];
            c[i]++;
        }
    }
    return (n==1) ? 0 : n;
}

inline ll POW(ll x,ll y,ll mod)
{
    ll ans=1;
    while (y)
    {
        if (y&1) ans=ans*x%mod;
        x=x*x%mod;
        y>>=1;
    }
    return ans;
}

void print(ll x)
{
    if (x==0) return;
    print(x/10);
    putchar(x%10+'0');
}

signed main()
{
    A=read(); B=read();
    get_prime();
    if (ll x=get_c()) c[++cnt]=1,zs[cnt]=x; //left
    ll ans=1;
    for (ll i=1;i<=cnt;i++)
    {
        if (!c[i]) continue;
        //a1=1,an=zs[i]^(B*c[i])
        ll mod=(zs[i]-1)*ha;
        ll an=POW(zs[i]%mod,B*c[i],mod);
        ll now=( (an*zs[i]-1)%mod )/(zs[i]-1); //(anq-a1)/q-1;
        ans=ans*now%ha;
    }
    print(ans);
    return 0;
}

新评论

称呼不能为空
邮箱格式不合法
网站格式不合法
内容不能为空