51nod 1363 最小公倍数之和

51nod 1363

原题连接:
https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1363

这个是一个不算很难的计算。

对于每次询问,给定 n

answer=i=1nlcm(i,n)

=i=1ningcd(i,n)=ni=1nigcd(i,n)

则有:

answer=ni=1nigcd(i,n)=nk|n(1ki=1n[gcd(i,n)=k]i)=nk|n(i=1n[gcd(i,n)=k]ik)=nk|n(i=1n[gcd(i,n)=k]ik)

因为这个时候 ik nk 互素

则:

answer=nk|n(i=1nk[ink]i)=nk|n(i=1k[ik]i)

记对于 1 n ,与 n 互素的 整数之和为 S(n)

S(n)=i=1n[in]i

当 有 tn 时, 则必然有: (nt)n

所以,当 n>1 时,每一个与 n 互素的整数 t 都 必然存在一个整数 u 有:

un    t+u=n

所以 n>1 时:

S(n)=ϕ(n)n2

n=1 时:

S(n)=1

所以:

answer=nk|nS(k)=n(1+k|n ,k>1ϕ(k)k2)=n2(2+k|n ,k>1ϕ(k)k)=n2(1+k|nϕ(k)k)

积性函数的和函数依然是积性函数。

而积性函数的值可以由其 因式分解后的素数幂形式得来。

f(n)=ϕ(n)n 就是一个积性函数。

f(pk)=(pkp(k1))pk 其中,k>1.

那么其和函数素数幂形式是两个等比数列求和。

计算得:

F(pk)=k|pkf(k)=p(p2k1p21pp2k1p21)+1

(注:貌似暴力分解不会超时。也算是暴力题了)

#include 
#include 
#include 

using namespace std;
typedef long long LL;

const LL mod=1e9+7;

LL P(LL a,int b)
{
    LL tmp=1;
    while(b)
    {
        if(b&1)
            tmp=tmp*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return tmp;
}

LL F(LL p,int k)
{
    LL Iv=P((p*p%mod-1+mod)%mod,mod-2);
    LL S=(P(p,k<<1)-1+mod)%mod;
    S=S*Iv%mod;
    S=p*(S*p%mod-S+mod)%mod;
    return (S+1)%mod;
}
int main ()
{
    int T;
    LL Iv=P(2,mod-2);
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        LL N=(LL)n;
        LL ans=1;
        for(int i=2;i*i<=n;i++)
        {
            if(n%i) continue;
            int k=0;
            while(n%i==0)
            {
                k++;
                n/=i;
            }
            ans*=F((LL)i,k);
            ans%=mod;
        }

        if(n>1)
            ans=(ans*F((LL)n,1))%mod;
        printf("%lld\n",(((LL)1+ans)%mod)*N %mod * Iv % mod);
    }
    return 0;
}

你可能感兴趣的:(刷题小结)