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

题目描述

i=1nj=1n(i,j) mod (1e9+7)n<=1010\sum_{i=1}^n\sum_{j=1}^n(i,j)~mod~(1e9+7)\\n<=10^{10}

题目分析

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

AC Code
#include <cstdio>
#include <map>
#include <cstring>
#include <algorithm>
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);
}
posted @ 2019-12-14 14:52  _Ark  阅读(128)  评论(0编辑  收藏  举报