JZOJ4872. 太阳神

题目大意

给定一个 n ,求有多少对 (a,b) 满足 an,bn,lcm(a,b)>n

Data Constraint
n1010

题解

直接计算不太好算。考虑用所有 n2 的方案减去不合法的方案。
现在要求 ni=1nj=1[i×j(i,j)n]
d=(i,j)
易得 nd=1ni=1nj=1[(i,j)=1][i×j×dn]
莫比乌斯反演一波: nd=1nk=1μ(k)ni=1nj=1[i×j×dnk2]
转换主体: nk=1μ(k)nd=1ni=1nj=1[i×j×dnk2]
前面是根号的,现在要求后面那一部分,也就是求 a=1b=1c=1abcn
分类讨论即可。假设 abc ,那么 a[1,n13] b[1,na] ,暴力枚举 a,b 统计即可。通过积分可以算出,这个部分的复杂度是 O(n16)

时间复杂度: O(n23)

SRC

#include
#include
#include
#include
#include
#include
using namespace std ;

#define N 100000 + 10
typedef long long ll ;
const int MO = 1e9 + 7 ;

bool flag[N] ;
int Pri[N] , miu[N] ;
ll n , ans ;

void Pre() {
    miu[1] = 1 ;
    for (int i = 2 ; i < N ; i ++ ) {
        if ( !flag[i] ) {
            Pri[++Pri[0]] = i ;
            miu[i] = -1 ;
        }
        for (int j = 1 ; j <= Pri[0] ; j ++ ) {
            if ( i * Pri[j] >= N ) break ;
            flag[i*Pri[j]] = 1 ;
            if ( i % Pri[j] == 0 ) { miu[i*Pri[j]] = 0 ; break ; }
            else miu[i*Pri[j]] = -miu[i] ;
        }
    }
}

ll Solve( ll c ) {
    ll ret = 0 ;
    for (int a = 1 ; (ll)a * a * a <= c ; a ++ ) {
        ret = (ret + 3ll * (c / a / a - a) % MO + 1ll) % MO ;
        int UP = sqrt( c / a ) ;
        for (int b = a + 1 ; b <= UP ; b ++ ) {
            ret = (ret + 6ll * (c / a / b - b) % MO + 3ll) % MO ;
        }
    }
    return ret ;
}

int main() {
    freopen( "ra.in" , "r" , stdin ) ;
    freopen( "ra.out" , "w" , stdout ) ;
    Pre() ;
    scanf( "%lld" , &n ) ;
    ans = 0 ;
    int UP = sqrt(n) ;
    for (int i = 1 ; i <= UP ; i ++ ) {
        ans = (ans + (ll)miu[i] * Solve( n / i / i ) % MO + MO) % MO ;
    }
    n %= MO ;
    ans = (n * n % MO - ans + MO) % MO ;
    printf( "%lld\n" , ans ) ;
    return 0 ;
}

以上.

你可能感兴趣的:(莫比乌斯反演)