51nod 1237 最大公约数之和 V3

时间:2021-06-06 20:19:32

求∑1<=i<=n1<=j<=ngcd(i,j) % P

P = 10^9 + 7

2 <= n <= 10^10

这道题,明显就是杜教筛

推一下公式:

利用∑d|nphi(d) = n

ans = ∑1<=i<=n1<=j<=nd|(i,j)phi(d)

= ∑1<=d<=n1<=i<=n1<=j<=n[d|(i,j)]phi(d)

= ∑1<=d<=nphi(d)∑1<=i<=n1<=j<=n[d|(i,j)]

= ∑1<=d<=nphi(d)(n / d) * (n / d)

= ∑1<=i<=nphi(i) * (n / i) * (n / i)

这样我们就可以把i按照(n / i)分成sqrt(n)段,假如此时x = n / i,r = n / x

则[i,r]这段的(n / i)都为x,则此时的贡献为x * x * ∑i<=j<=rphi(j)

这样的我们对于每一段,我们需要算[i,r]这一段的phi函数之和

令g(n) = ∑1<=i<=nphi(i)

则我们需要算的是g(r) - g(i - 1)

那怎么算g(r)呢?因为这个时候r可能非常大

我们知道:

g(n) = n * (n + 1) / 2 - ∑2<=i<=ng(n / i)

所以我们可以在O(n^(2/3))内等到g(n)

本来我以为这样需要算sqrt(n)段,每一段最坏是O(n^(2/3)),所以时间复杂度是不行的,

但是试写一下代码,交后,发现跑的很快,大概是有很多段的g都可以很快的求出来???

我这里也不会算复杂度。。。

代码:

  //File Name: nod1237.cpp
//Created Time: 2017年01月04日 星期三 00时47分02秒 #include <bits/stdc++.h>
#define LL long long
using namespace std;
const int MAXN = (int)2e7 + ;
const int P = (int)1e9 + ;
bool check[MAXN];
int prime[MAXN / ];
LL g[MAXN],inv_2;
map<LL,LL> rem;
void init(int n){
int tot = ;
g[] = ;
memset(check,false,sizeof(check));
for(int i=;i<=n;++i){
if(!check[i]){
prime[tot++] = i;
g[i] = i - ;
}
for(int j=;j<tot;++j){
if((LL)i * prime[j] > n) break;
check[i * prime[j]] = true;
if(i % prime[j] == ){
g[i * prime[j]] = g[i] * prime[j] % P;
break;
}
else{
g[i * prime[j]] = g[i] * (prime[j] - ) % P;
}
}
}
for(int i=;i<=n;++i)
g[i] = (g[i] + g[i - ]) % P;
}
LL cal_g(LL n){
if(n < MAXN) return g[n];
if(rem.count(n)) return rem[n];
LL res = (n % P) * ((n + ) % P) % P * inv_2 % P;
for(LL i=,x,r;i<=n;){
x = n / i;
r = n / x;
res = (res - (r - i + ) % P * cal_g(x) % P + P) % P;
i = r + ;
}
rem[n] = res;
return res;
}
LL solve(LL n){
init(min(n,MAXN - 1LL));
LL res = ;
for(LL i=,x,r;i<=n;){
x = n / i;
r = n / x;
res = (res + (x % P) * (x % P) % P * (cal_g(r) - cal_g(i - ) + P) % P) % P;
i = r + ;
}
return res;
}
LL qp(LL x,LL y){
LL res = ;
for(;y>;y>>=){
if(y & ) res = res * x % P;
x = x * x % P;
}
return res;
}
int main(){
inv_2 = qp(,P - );
LL n;
scanf("%lld",&n);
printf("%lld\n",solve(n));
return ;
}