[51Nod 1220] - 约数之和 (杜教筛)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Ike940067893/article/details/84996397

题面

d ( n ) d(n) 表示 n n 的约数之和求
i = 1 n j = 1 n d ( i j ) \large\sum_{i=1}^n\sum_{j=1}^nd(ij)

题目分析

先给结论
d ( i j ) = x i y j x j / y [ ( x , y ) = = 1 ] \large d(ij)=\sum_{x|i}\sum_{y|j}xj/y[(x,y)==1]
可以通过 传送门 类似的证明方法证明
拖更…

AC code
#include <cstdio>
#include <map>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN = 1e6 + 1, mod = 1e9 + 7;
int Prime[MAXN/10], Cnt, mu[MAXN];
bool IsnotPrime[MAXN];
inline void init(int n)
{
	mu[1] = 1;
	for(int i = 2; i <= n; ++i)
	{
		if(!IsnotPrime[i])
			Prime[++Cnt] = i, mu[i] = -1;
		for(int j = 1, v; j <= Cnt && i * Prime[j] <= n; ++j)
		{
			v = i * Prime[j];
			IsnotPrime[v] = 1;
			if(i % Prime[j] == 0) { mu[v] = 0; break; }
			mu[v] = -mu[i];
		}
	}
	for(int i = 1; i <= n; ++i)
		mu[i] = (mu[i-1] + i*mu[i]%mod) % mod;
}
map<int, int>s;

inline int f(int i, int j) //i+(i+1)+...+j
{
	return ((LL)(i+j) * (j-i+1)/2) % mod;
}

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

inline int calc(int n)
{
	int ret = 0, k;
	for(int i = 1, j; i <= n; i=j+1)
	{
		j = n/(n/i); k = n/i;
		ret = (ret + (LL)(j-i+1) * (((LL)k*(k+1)/2)%mod) % mod) % mod;
	}
	return ret;
}

inline int solve(int n)
{
	int ret = 0, last = 0, tmp, tmp2;
	for(int i = 1, j; i <= n; i=j+1)
	{
		tmp = sum(j = n/(n/i)), tmp2 = calc(n/i), tmp2 = (LL)tmp2 * tmp2 % mod;
		ret = (ret + (LL)(tmp - last) * tmp2 % mod) % mod;
		last = tmp;
	}
	return ret;
}

int main ()
{
	int n; init(MAXN-1);
	scanf("%d", &n);
	printf("%d\n", (solve(n)+mod)%mod);
}

猜你喜欢

转载自blog.csdn.net/Ike940067893/article/details/84996397