[51Nod 1237] 最大公约数之和 (杜教筛+莫比乌斯反演)

题目描述

∑ i = 1 n ∑ j = 1 n ( i , j )   m o d   ( 1 e 9 + 7 ) n < = 1 0 10 \sum_{i=1}^n\sum_{j=1}^n(i,j)~mod~(1e9+7)\\n<=10^{10} i=1nj=1n(i,j) mod (1e9+7)n<=1010

题目分析

乍一看十分像裸莫比乌斯反演,然而 n n n的范围让人望而却步
于是先变化一下式子
A n s = ∑ i = 1 n ∑ j = 1 n ( i , j ) Ans=\sum_{i=1}^n\sum_{j=1}^n(i,j) Ans=i=1nj=1n(i,j)
枚举 T = ( i , j ) T=(i,j) T=(i,j)
= ∑ T = 1 n ∑ i = 1 ⌊ n T ⌋ ∑ j = 1 ⌊ n T ⌋ [ ( i , j ) = = 1 ] = ∑ T = 1 n ∑ i = 1 ⌊ n T ⌋ ∑ j = 1 ⌊ n T ⌋ ∑ d ∣ i , d ∣ j μ ( d ) = ∑ T = 1 n T ∑ d = 1 ⌊ n T ⌋ μ ( d ) ⌊ n T d ⌋ 2 =\sum_{T=1}^n\sum_{i=1}^{\lfloor\frac nT\rfloor}\sum_{j=1}^{\lfloor\frac nT\rfloor}[(i,j)==1]\\=\sum_{T=1}^n\sum_{i=1}^{\lfloor\frac nT\rfloor}\sum_{j=1}^{\lfloor\frac nT\rfloor}\sum_{d|i,d|j}\mu(d)\\=\sum_{T=1}^nT\sum_{d=1}^{\lfloor\frac nT\rfloor}\mu(d){\lfloor\frac n{Td}\rfloor}^2 =T=1ni=1Tnj=1Tn[(i,j)==1]=T=1ni=1Tnj=1Tndi,djμ(d)=T=1nTd=1Tnμ(d)Tdn2
令k=Td
= ∑ k = 1 n ⌊ n k ⌋ 2 φ ( k ) =\sum_{k=1}^n{\lfloor\frac n{k}\rfloor}^2\varphi(k) =k=1nkn2φ(k)
则此时可以整除分块优化,每次算出 ⌊ n k ⌋ {\lfloor\frac n{k}\rfloor} kn相等的上下界 i , j i,j i,j后用莫比乌斯反演计算 ( S φ ( j ) − S φ ( i − 1 ) ) (S\varphi(j)-S\varphi(i-1)) (Sφ(j)Sφ(i1))
由于计算 φ \varphi φ的前缀和时记忆化处理过,所以在杜教筛外面再套了一个整除分块优化不会影响时间复杂度,复杂度仍是 Θ ( n 2 3 ) \Theta(n^{\frac23}) Θ(n32)

AC Code
#include 
#include 
#include 
#include 
using namespace std;
typedef long long LL;
const int mod = 1e9+7;
const int MAXN = 5e6+1;
const int inv2 = 500000004;
map<LL, LL> S; LL s[MAXN];
int Prime[MAXN], Cnt, phi[MAXN];
bool IsnotPrime[MAXN];

void init()
{
	phi[1] = 1;
	for(int i = 2; i < MAXN; ++i)
	{
		if(!IsnotPrime[i]) Prime[++Cnt] = i, phi[i] = i-1;
		for(int j = 1; j <= Cnt && i * Prime[j] < MAXN; ++j)
		{
			IsnotPrime[i * Prime[j]] = 1;
			if(i % Prime[j] == 0)
			{
				phi[i * Prime[j]] = phi[i] * Prime[j];
				break;
			}
			phi[i * Prime[j]] = phi[i] * phi[Prime[j]];
		}
	}
	for(int i = 1; i < MAXN; ++i) s[i] = (s[i-1] + phi[i]) % mod;
}

inline LL sum(LL n)
{
	if(n < MAXN) return s[n];
	if(S.count(n)) return S[n];
	LL ret = (n%mod) * ((n+1)%mod) % mod * inv2 % mod;
	for(LL i = 2, j; i <= n; i=j+1)
	{
		j = n/(n/i);
		ret = (ret - sum(n/i) * ((j-i+1)%mod) % mod) % mod;
	}
	return S[n] = ret;
}

inline LL solve(LL n)
{
	LL ret = 0;
	for(LL i = 1, j; i <= n; i=j+1)
	{
		j = n/(n/i);
		ret = (ret + ((n/i)%mod) * ((n/i)%mod) % mod * ((sum(j)-sum(i-1))%mod) % mod) % mod;
	}
	return ret;
}
int main ()
{
	init(); LL n;
	scanf("%lld", &n);
	printf("%lld\n", (solve(n)+mod)%mod);
}

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