luogu3768 简单的数学题

题目链接

问题分析

题目就是要求

[Ans=sum_{i=1}^nsum_{j=1}^nijgcd(i,j) ]

首先乱搞一波:

[egin{aligned} Ans&=sum_{t=1}^nsum_{i=1}^nsum_{j=1}^nijt[gcd(i,j)==t]\ &=sum_{t=1}^nt^3sum_{i=1}^{lfloorfrac{n}{t} floor}sum_{j=1}^{lfloorfrac{n}{t} floor}ij[gcd(i,j)==1] end{aligned} ]

然后对后面那一部做莫比乌斯反演:

[f(d)=sum_{i=1}^nsum_{j=1}^nij[gcd(i,j)==1]\ F(d)=sum_{i=1}^nsum_{j=1}^nij[d|gcd(i,j)]=d^2sum_{i=1}^{lfloorfrac{n}{d} floor}sum_{j=1}^{lfloorfrac{n}{d} floor}ij\ F(d)=sum_{d|k}f(k)\ f(d)=sum_{d|k}mu(frac{k}{d})F(k)=sum_{d|k}mu(frac{k}{d})k^2sum_{i=1}^{lfloorfrac{n}{k} floor}sum_{j=1}^{lfloorfrac{n}{k} floor}ij\ f(1)=sum_{k=1}^nmu(k)k^2sum_{i=1}^{lfloorfrac{n}{k} floor}sum_{j=1}^{lfloorfrac{n}{k} floor}ij=sum_{k=1}^nmu(k)k^2(sum_{i=1}^{lfloorfrac{n}{k} floor}i)^2 ]

那么就有:

[Ans=sum_{t=1}^{n}t^3sum_{k=1}^{n/t}mu(k)k^2(sum_{i=1}^{lfloorfrac{n}{tk} floor}i)^2 ]

(K=tk)

[egin{aligned} Ans&=sum_{K=1}^nsum_{t|K}tmu(frac{K}{t})K^2(sum_{i=1}^{lfloorfrac{n}{K} floor}i)^2\ &=sum_{K=1}^nK^2(sum_{i=1}^{lfloorfrac{n}{K} floor}i)^2sum_{t|K}tmu(frac{K}{t}) end{aligned} ]

因为(phi*1=id_1)(1*mu=e),所以(id_1*mu=phi*1*mu=phi*e=phi)。(其中(*)表示狄利克雷卷积)

那么

[sum_{t|K}frac{K}{t}mu(t)=phi(K)\ Ans=sum_{K=1}^nK^2(sum_{i=1}^{lfloorfrac{n}{K} floor}i)^2sum_{t|K}frac{K}{t}mu(t)=sum_{K=1}^n(sum_{i=1}^{lfloorfrac{n}{K} floor}i)^2K^2phi(K) ]

其中((sum_{i=1}^{lfloorfrac{n}{K} floor}i)^2)可以整除分块,后面我们考虑杜教筛:

[f(n)=n^2phi(n)\ S(n)=sum_{i=1}^nf(i)\ g(1)S(n)=sum_{i=1}^n(g*f)(i)-sum_{i=2}^ng(i)S(lfloorfrac{n}{i} floor)\ g=id_2\ S(n)=sum_{i=1}^ni^3-sum_{i=2}^ni^2S(lfloorfrac{n}{i} floor) ]

那么就可以啦!时间复杂度(O(n^{frac{2}{3}}))

参考程序

这个写法不优良,时间复杂度是 (O(n^{frac{3}{4}})) 的。还要带上一个 map 的大常数 log ?

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

const LL Maxn066 = 6000000;
LL Phi[ Maxn066 + 10 ], Vis[ Maxn066 + 10 ], Prime[ Maxn066 ], Count;
LL Mod, n, Ans, Inv6;

void EulerSieve();
void Cal();
LL Inv( LL a );

int main() {
    scanf( "%lld%lld", &Mod, &n );
    Inv6 = Inv( 6 );
    EulerSieve();
    Cal();
    return 0;
}

void EulerSieve() {
    Phi[ 1 ] = 1;
    for( LL i = 2; i <= Maxn066; ++i ) {
        if( !Vis[ i ] ) {
            Phi[ i ] = i - 1;
            Prime[ ++Count ] = i;
        }
        for( LL j = 1; j <= Count && Prime[ j ] * i <= Maxn066; ++j ) {
            Vis[ Prime[ j ] * i ] = 1;
            if( !( i % Prime[ j ] ) ) {
                Phi[ Prime[ j ] * i ] = Phi[ i ] * Prime[ j ] % Mod;
                break;
            }
            Phi[ Prime[ j ] * i ] = Phi[ i ] * Phi[ Prime[ j ] ] % Mod;
        }
    }
    for( LL i = 2; i <= Maxn066; ++i ) Phi[ i ] = ( Phi[ i - 1 ] + Phi[ i ] * i % Mod * i % Mod ) % Mod;
    return;
}

map< LL, LL > Map;

LL S( LL Key ) {
    if( Key <= Maxn066 ) return Phi[ Key ];
    if( Map.find( Key ) != Map.end() ) return Map[ Key ];
    LL Ans = Key % Mod * ( Key % Mod + 1 ) / 2 % Mod; Ans = Ans * Ans % Mod;
    for( LL i = 2, j; i <= Key; i = j + 1 ) {
        j = Key / ( Key / i );
        LL T = j % Mod * ( j % Mod + 1 ) % Mod * ( 2 * j % Mod + 1 ) % Mod * Inv6 % Mod;	
        T = T - ( i % Mod - 1 ) * ( i % Mod ) % Mod * ( 2 * i % Mod - 1 ) % Mod * Inv6 % Mod;
        T = ( T % Mod + Mod ) % Mod;
        T = T * S( Key / i ) % Mod;
        Ans = ( ( Ans - T ) % Mod + Mod ) % Mod;
    }
    Map[ Key ] = Ans;
    return Ans;
}

void Cal() {
    for( LL i = 1, j; i <= n; i = j + 1 ) {
        j = n / ( n / i );
        LL T = ( 1 + n / i % Mod ) * ( n / i % Mod ) / 2 % Mod; T = T * T % Mod;
        LL Delta = ( ( S( j ) - S( i - 1 ) ) % Mod + Mod ) % Mod;
        Ans = ( Ans + T * Delta % Mod ) % Mod;
    }
    printf( "%lld
", Ans );
    return;
}

void Exgcd( LL a, LL b, LL &x, LL &y ) {
    if( b == 0 ) {
        x = 1; y = 0; return;
    }
    Exgcd( b, a % b, y, x );
    y -= a / b * x;
    return;
}

LL Inv( LL a ) {
    LL x, y;
    Exgcd( a, Mod, x, y );
    if( x < 0 ) x += Mod;
    return x;
}

原文地址:https://www.cnblogs.com/chy-2003/p/10443094.html