题目大意
给定一个
n
,求有多少对
Data Constraint
n≤1010
题解
直接计算不太好算。考虑用所有
n2
的方案减去不合法的方案。
现在要求
∑ni=1∑nj=1[i×j(i,j)≤n]
令
d=(i,j)
易得
∑nd=1∑ni=1∑nj=1[(i,j)=1][i×j×d≤n]
莫比乌斯反演一波:
∑nd=1∑nk=1μ(k)∑ni=1∑nj=1[i×j×d≤nk2]
转换主体:
∑n√k=1μ(k)∑nd=1∑ni=1∑nj=1[i×j×d≤nk2]
前面是根号的,现在要求后面那一部分,也就是求
∑a=1∑b=1∑c=1abc≤n
分类讨论即可。假设
a≤b≤c
,那么
a∈[1,n13]
,
b∈[1,na−−√]
,暴力枚举
a,b
统计即可。通过积分可以算出,这个部分的复杂度是
O(n16)
时间复杂度: O(n23)
SRC
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
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 ;
}
以上.