狄利克雷卷积与杜教筛

狄利克雷卷积。
就和多项式的卷积一样。
多项式是 g ( x ) × h ( x ) = ∑ a + b = x   a n d   a , b ∈ N g ( a ) ∗ h ( b ) g(x) \times h(x)= \sum_{a+b = x\ and \ a,b\in \N} g(a) * h(b) g(x)×h(x)=a+b=x and a,bNg(a)h(b)
而狄利克雷卷积是 g ( x ) × h ( x ) = ∑ a ∗ b = x   a n d   a , b ∈ N + g ( a ) ∗ h ( b ) g(x) \times h(x) = \sum_{a*b = x \ and \ a,b\in \N_+ } g(a) * h(b) g(x)×h(x)=ab=x and a,bN+g(a)h(b)
而莫比乌斯反演就是基于 I × μ = e I \times \mu = e I×μ=e
其中
I ( x ) = 1 , e ( x ) = [ x = = 1 ] I(x) = 1 , e(x) = [x == 1] I(x)=1,e(x)=[x==1]
e ( x ) e(x) e(x)是莫比乌斯的单位元。

而积性函数的前缀和的快速算法1则是基于这样一个事实:
∵ ∑ a ∗ b < = x f ( a ) ∗ g ( b ) = ∑ 1 < = a < = x g ( a ) ∗ s u m f ( ⌊ x / a ⌋ ) ∴ s u m f ( x ) ∗ g ( 1 ) = ∑ a ∗ b < = x f ( a ) ∗ g ( b ) − ∑ 1 < = a < x g ( a ) ∗ s u m f ( ⌊ x / a ⌋ ) \because \sum_{a*b<=x} f(a) * g(b) = \sum_{1<=a<=x} g(a) * sumf(\lfloor x/a \rfloor) \\ \therefore sumf(x) * g(1) = \sum_{a*b<=x} f(a) * g(b) - \sum_{1<=a<x} g(a) * sumf(\lfloor x/a \rfloor) ab<=xf(a)g(b)=1<=a<=xg(a)sumf(x/a)sumf(x)g(1)=ab<=xf(a)g(b)1<=a<xg(a)sumf(x/a)

只要能快速算出右边的且 g ( 1 ) ≠ 0 g(1)\neq 0 g(1)=0就能求解。
先放一个大佬的水表
http://www.cnblogs.com/cjyyb/category/1124706.html

1.莫比乌斯函数之和
g = I g = I g=I
ACCode:

#include<bits/stdc++.h>
#define LL long long
using namespace std;

/*

g(x) = 1
f(x) * g(x) = [x == 1]
sum(f(x) * g(x)) = 1;

*/

map<LL,int>mp;

LL n,m;

#define ts 10000005
LL mu[ts];
int pr[ts/8],cnt_pr;
bool vis[ts];
void sieve()
{
	mu[1] = 1;
	for(int i=2,lim = min(ts*1ll,m+1);i<lim;i++)
	{
		if(!vis[i]) pr[cnt_pr++] = i , mu[i] = -1;
		for(int j=0;j<cnt_pr && pr[j] * i < lim;j++)
		{
			vis[i * pr[j]] = 1;
			if(i % pr[j] == 0) break;
			mu[i * pr[j]] = -mu[i];
		}
		mu[i] += mu[i-1];
	}
}

LL solve(LL n)
{
	if(n <= ts) return mu[n];
	LL tmp;
	if(mp.count(n)) return mp[n];
	tmp = 1;
	for(LL i=2,nxt;i<=n;i=nxt+1)
	{
		nxt = n / (n / i);
		tmp = (tmp - (nxt - i + 1) * solve(n/i));
	}
	mp[n] = tmp;
	return tmp;
}

int main()
{
	scanf("%lld%lld",&n,&m);
	sieve();
	printf("%lld\n",solve(m)-solve(n-1));
}

2.欧拉函数之和。
g = I , s u m ( f ∗ g ) ( n ) = n ∗ ( n + 1 ) / 2 g = I , sum(f * g)(n) = n * (n+1) / 2 g=I,sum(fg)(n)=n(n+1)/2

#include<bits/stdc++.h>
#define LL long long
#define mod 1000000007
using namespace std;

/*

g(x) = 1
f(x) * g(x) = [x == 1]
sum(f(x) * g(x)) = 1;

*/

LL n,m;

#define ts 5000005
LL phi[ts],phi2[100005];
int pr[ts/8],cnt_pr;
bool vis[ts];
void sieve()
{
	phi[1] = 1;
	for(int i=2,lim = min(ts*1ll,n+1);i<lim;i++)
	{
		if(!vis[i]) pr[cnt_pr++] = i , phi[i] = i-1;
		for(int j=0;j<cnt_pr && pr[j] * i < lim;j++)
		{
			vis[i * pr[j]] = 1;
			if(i % pr[j] == 0){ phi[i*pr[j]] = phi[i] * pr[j];break;}
			phi[i * pr[j]] = phi[i] * (pr[j] - 1);
		}
		phi[i] += phi[i-1];
	}
}

LL N;
LL solve(LL n)
{
	if(n <= ts) return phi[n];
	int loc = N / n;
	if(phi2[loc] != phi2[0]) return phi2[loc];
	LL tmp = ((n&1) ? (n%mod*((n+1)/2)) : (n/2%mod * ((n+1)%mod))) % mod;
	for(LL i=2,nxt;i<=n;i=nxt+1)
	{
		nxt = n / (n / i);
		tmp = (tmp - (nxt - i + 1) % mod * solve(n/i)) % mod;
	}
	phi2[loc] = tmp;
	return tmp;
}

int main()
{
	scanf("%lld",&n);
	sieve();
	memset(phi2,0x7f,sizeof phi2);
	N = n;
	printf("%lld\n",(solve(n)+mod)%mod);
}

bzoj 3944 sum
LL 好恶心。
常数很大。

#include<bits/stdc++.h>
#define LL long long
using namespace std;

LL n;

#define ts 5000005
int mu[ts],pr[ts/3],cnt_pr;
bool vis[ts];
LL phi[ts];

void sieve()
{
	mu[1] = phi[1] = 1;
	for(int i=2;i<ts;i++)
	{
		if(!vis[i]) pr[cnt_pr++] = i, mu[i] = -1,phi[i] = i-1;
		for(int j=0;j<cnt_pr && pr[j] * i < ts;j++)
		{
			vis[i * pr[j]] = 1;
			if(i % pr[j] == 0){ phi[i*pr[j]] = phi[i] * pr[j]; break; }
			phi[i*pr[j]] = phi[i] * (pr[j] - 1);
			mu[i * pr[j]] = -mu[i];
		}
		mu[i] += mu[i-1];
		phi[i] += phi[i-1];
	}
}

namespace Phi
{
	LL f[100005];
	int vis[100005],tot;
	LL solve(LL N)
	{
		if(N < ts) return phi[N];
		int loc = n / N;
		if(vis[loc] == tot) return f[loc];
		f[loc] = N * (N+1) / 2;
		for(int i=2,nxt=0;i<=N && nxt<N;i=nxt+1)
		{
			nxt = N/(N/i);
			f[loc] = f[loc] - (nxt - i + 1) * solve(N/i);
		}
		vis[loc] = tot;
		return f[loc];
	}
}

namespace Mu
{
	LL f[100005];
	int vis[100005],tot;
	LL solve(LL N)
	{
		if(N<ts) return mu[N];
		int loc = n / N;
		if(vis[loc] == tot) return f[loc];
		f[loc] = 1;
		for(int i=2,nxt=0;i<=N && nxt<N;i=nxt+1)
		{
			nxt = N / (N / i);
			f[loc] = f[loc] - (nxt - i + 1) * solve(N/i);
		}
		vis[loc] = tot;
		return f[loc];
	}
}

int main()
{
	sieve();
	int T;
	for(scanf("%d",&T);T--;)
	{
		scanf("%lld",&n);
		Mu::tot++;
		Phi::tot++;
		printf("%lld %lld\n",Phi::solve(n),Mu::solve(n));
	}
}

hdu 5608 function
我主要说一下, ∑ i = 1 x n 2 + 3 n + 2 = x ∗ ( x − 1 ) ∗ ( x − 2 ) / 3 = x 3 ‾ / 3 \sum_{i=1}^xn^2+3n+2 = x * (x-1) * (x-2) / 3 = x^{\underline3}/3 i=1xn2+3n+2=x(x1)(x2)/3=x3/3
然后这种和因数有关的函数可以 O ( n l o g n ) O(nlogn) O(nlogn)筛。。。。
我用的 O ( n n ) O(n\sqrt{n}) O(nn )
这个是一个离散微积分的基本结论

#include<bits/stdc++.h>
#define LL long long
#define mod 1000000007
using namespace std;

#define ts 100005
LL f[100005];
map<int,int>mp;
int solve(int n)
{
	if(n < ts) return f[n];
	if(mp.count(n)) return mp[n];
	LL ret = 1ll * (n-2) * (n-1) % mod * n % mod * 333333336ll % mod;
	for(int i=2,nxt;i<=n;i=nxt+1)
	{
		nxt = n/(n/i);
		ret =(ret - 1ll * (nxt - i + 1) * solve(n / i)) % mod;
	}
	ret = (ret%mod+mod)%mod;
	mp[n] = ret;
	return ret;
}

void sieve()
{
	for(int i=2;i<ts;i++)
	{
		f[i] = (1ll * i * i - 3ll * i + 2) % mod;
		for(int j=2;j*j<=i;j++)
			if(i % j == 0)
			{
				f[i] -= f[j];
				if(j * j != i) f[i] -= f[i/j];
			}
		f[i] =(f[i] % mod + mod) % mod;
	}
	for(int i=2;i<ts;i++)
		f[i] = ((f[i] + f[i-1]) % mod + mod ) % mod;
}

int main()
{
	sieve();
	int T;
	for(scanf("%d",&T);T--;)
	{
		int n;
		scanf("%d",&n);
		printf("%d\n",solve(n));
	}
}

51nod 1237

给出一个数N,输出小于等于N的所有数,两两之间的最大公约数之和。
相当于计算这段程序(程序中的gcd(i,j)表示i与j的最大公约数):
由于结果很大,输出Mod 1000000007的结果。
G = 0 ; f o r ( i = 1 ; i < N ; i + + ) f o r ( j = 1 ; j < = N ; j + + ) G = ( G + g c d ( i , j ) ) N < = 1 0 1 0 G=0;\\ for(i=1;i<N;i++)\\ for(j=1;j<=N;j++)\\ {\\ G = (G + gcd(i,j)) % 1000000007;\\ }\\ N<=10^10\\ G=0;for(i=1;i<N;i++)for(j=1;j<=N;j++)G=(G+gcd(i,j))N<=1010

这个题揭露了杜教筛的另一个性质:
实际上求 s u m f ( n ) sumf(n) sumf(n)用到的 s u m f ( x ) sumf(x) sumf(x)满足 x = ⌊ n k ⌋ , k ∈ N ∗ x = \lfloor \frac nk \rfloor , k \in N^* x=kn,kN
根据整除分块可以知道只有 O ( n ) O(\sqrt n) O(n )个x。
这个题的答案是:
2 ∗ ∑ i = 1 n i ∗ ∑ j = 1 ⌊ n i ⌋ φ ( j ) − ∑ i = 1 n i 2 * \sum_{i=1}^ni *\sum_{j=1}^{\lfloor \frac ni \rfloor} \varphi(j) - \sum_{i=1}^ni 2i=1nij=1inφ(j)i=1ni
这个分块优化套杜教筛之后也只会用到 O ( n ) O(\sqrt n) O(n ) s u m φ ( x ) sum\varphi(x) sumφ(x)
所以还是 O ( n 2 3 ) O(n^{\frac 23}) O(n32)
(我代码中的记忆化存储方法也可以用这个结论证明是不会撞的,尽管没快多少,除法的常数。。。。。)
AC Code:

#include<bits/stdc++.h>
#define LL long long
using namespace std;

/*

f(d) = d * g(n/d , m/d)
= d * sigma((1<=i<=n/d , 1<=j<=n/d) [gcd(i,j)==1])
= d * (sigma((1<=i<=n/d , phi(i)) * 2) - d

sigma(1<=d<=n,f(d)) 
= 2 * sigma(1<=i<=n,phi(i) * (n / i)) - (n+1) * n / 2
= 2 * sigma(1<=i<=n,i * sigma(k<=n/i,phi(k))) - (n+1) * n / 2
*/

LL n;



#define ts 5000005
#define mod 1000000007

LL calc(LL a,LL b)
{
	LL c = a + b;
	LL d = b - a + 1;
	if(c & 1) d/=2;
	else c/=2;
	c%=mod,d%=mod;
	return d * c % mod ; 
}
int pr[ts],cnt_pr;
bool vis[ts];
LL phi[ts],f[ts];
void sieve()
{
	phi[1] = 1;
	for(int i=2;i<ts;i++)
	{
		if(!vis[i]) pr[cnt_pr++] = i , phi[i] = i-1;
		for(int j=0;j<cnt_pr && pr[j] * i < ts;j++)
		{
			vis[i * pr[j]] = 1;
			if(i % pr[j] == 0){ phi[i * pr[j]] = phi[i] * pr[j]; break; }
			phi[i * pr[j]] = phi[i] * (pr[j] - 1);
		}
		phi[i] = (phi[i] + phi[i-1]) % mod;
	}
}

LL solve(LL m)
{
	if(m <  ts) return phi[m];
	int loc = n / m;
	if(f[loc]!=-1) return f[loc];
	int tmp = calc(1,m);
	for(LL i=2,nxt;i<=m;i=nxt+1)
	{
		nxt = m/(m/i);
		tmp = (tmp - (nxt - i + 1) % mod * solve(m/i)) % mod;
	}
	return f[loc] = (tmp + mod) % mod;
}



int main()
{
	sieve();
	memset(f,-1,sizeof f);
	scanf("%lld",&n);
	LL ans = 0;
	for(LL i=1,nxt;i<=n;i=nxt+1)
	{
		nxt = n/(n/i);
		ans = (ans + calc(i,nxt) * solve(n/i)) % mod;
	}
	ans = (2ll * ans) % mod;
	ans = (ans - calc(1,n)) % mod;
	printf("%lld\n",(ans+mod)%mod);
}

51nod 1238
这个题整死我了。
在这个题中,我们能以更一般性的视角来看杜教筛,再也不是拿个 I I I就来卷就行的了。

出一个数N,输出小于等于N的所有数,两两之间的最小公倍数之和。
相当于计算这段程序(程序中的lcm(i,j)表示i与j的最小公倍数):
由于结果很大,输出Mod 1000000007的结果。
G=0;
for(i=1;i<N;i++)
for(j=1;j<=N;j++)
{
G = (G + lcm(i,j)) % 1000000007;
}

在jzptab(和这个题只有数据范围不同的一个题)中,我们可以推出这个式子
a n s = ∑ d = 1 n ( ⌊ n d ⌋ ∗ ( ⌊ n d ⌋ + 1 ) / 2 ) 2 ∗ ∑ p ∣ d μ ( p ) ∗ p ∗ p ∗ d p ans = \sum_{d=1}^n\left(\lfloor\frac nd\rfloor * (\lfloor\frac nd\rfloor + 1) / 2 \right )^2 * \sum_{p|d}\mu(p) * p * p* \frac dp ans=d=1n(dn(dn+1)/2)2pdμ(p)pppd
前面这个其实是不好动的,但是我们可以对前面的分块优化。
那么只需要求后面的前缀和就行了。(这里换一下正规的符号) f ∘ g = ∑ x ∑ p ∣ x f ( p ) ∗ g ( x p ) f ⋅ g = ∑ x f ( x ) × g ( x ) f \circ g = \sum_x\sum_{p|x}f(p) * g(\frac xp)\\ f\cdot g = \sum_x f(x) \times g(x) fg=xpxf(p)g(px)fg=xf(x)×g(x)
后面的函数其实就是
f ( x ) = ( i d ⋅ i d ⋅ μ ) ∘ i d f(x) = (id \cdot id \cdot \mu) \circ id f(x)=(ididμ)id
然后认真研究一下这个函数
你会发现:
( i d ⋅ i d ⋅ μ ) ∘ ( i d ⋅ i d ) = ∑ x ∑ p ∣ x p ∗ p ∗ μ ( p ) ∗ x p ∗ x p = ∑ x x 2 ∗ ∑ p ∣ x μ ( p ) (id \cdot id \cdot \mu) \circ (id \cdot id) = \sum_x\sum_{p|x}p*p*\mu(p)*\frac xp*\frac xp = \sum_x x^2 * \sum_{p|x} \mu(p) (ididμ)(idid)=xpxppμ(p)pxpx=xx2pxμ(p)
就是元函数嘛。。。。(这启示我们,寻找其他函数的逆元很重要,不要只知道 μ \mu μ I I I有,通过 ∘ \circ 来把 ⋅ \cdot 提出sigma也是很重要的)
然后把 f ( x ) f(x) f(x) i d ⋅ i d id\cdot id idid卷起来杜教筛就是了。
注意杜教筛中如 g ( 1 ) ≠ 1 g(1)\neq 1 g(1)=1还得求逆元(此题没有)
另外求前缀和的时候如果想卡常, s u m ( n x t ) − s u m ( i − 1 ) sum(nxt) - sum(i-1) sum(nxt)sum(i1)的后部分用一个变量存,初始时,杜教筛是从2开始的,初始值要小心。。。。。
网上别的解法用了
∑ i = 1 d [ ( i , d ) = = 1 ] ∗ i = ϕ ( d ) ∗ d + [ d = 1 ] 2 \sum_{i=1}^d [(i,d)==1]*i = \frac {\phi(d) * d + [d=1]} {2} i=1d[(i,d)==1]i=2ϕ(d)d+[d=1]
也很巧
AC Code:

#include<cstdio>
#include<algorithm>
#include<cstring>
#define LL long long
#define mod 1000000007
using namespace std;

/*

sigma(i,j,i * j / gcd(i,j))
= sigma(d , d * sigma(i,j,[gcd(i,j)==1] * i * j))
= sigma(d , d * sigma(p,mu[p] * S(n/d/p) * p * p))
= sigma(D , sigma(mu[p] * S(n/D) * p * p * D/p))
= sigma(D , S(n/D) * D * sigma(mu[p] * p));

f(x) = sigma(p|x , mu[p] * p * p * (x/p)) = (id.id.mu)*id
f*(id.id)
= (id . id . mu) * id * (id . id)
= (id . id . mu) * (id . id) * id
= sigma(x , sigma(p | x , p * p * mu[p] * x / p * x / p) ) * id
= sigma(x , x * x * sigma(p | x , mu[p]) ) * id
= sigma(x , x * x * [x==1]) * id
= id

sigf(n) * (id.id)(1) = sigma(i<=n,f*(id.id)(i)) - sigma(2<=i<=n,(id.id)(i) * sigf(n/i))

id.id(x) = x*x
*/

LL n;

#define ts 5000005
LL pf[ts],f[ts],pr[ts],cnt_pr;
bool vis[ts];

void sieve()
{
	pf[1] = 1;
	for(LL i=2;i<ts;i++)
	{
		if(!vis[i]) pr[cnt_pr++] = i , pf[i] = 1 - i;
		for(LL j=0;j<cnt_pr && pr[j] * i < ts;j++)
		{
			vis[i * pr[j]] = 1;
			if(i % pr[j] == 0)
			{
				pf[i * pr[j]] = pf[i];
				break;
			}
			pf[i * pr[j]] = 1ll * pf[i] * pf[pr[j]] % mod;
		}
	}
	for(LL i=2;i<ts;i++)
		pf[i] =( (1ll * pf[i] * i % mod + pf[i-1]) % mod + mod) % mod;
}

LL cal2(LL a,LL b)
{
	LL c = a+b , d = b-a+1;
	if(c & 1) d/=2;else c/=2;
	return (d % mod) * (c % mod) % mod;
}

LL cap2(LL m)
{
	int tmp;
	if(m>ts)
		tmp = m;
	LL a[3] = {m , m+1 , 2 * m + 1};
	for(LL i=0;i<3;i++) if(a[i] % 2 == 0)
	{
		a[i] /= 2;
		break;
	}
	for(LL i=0;i<3;i++) if(a[i] % 3 == 0)
	{
		a[i] /= 3;
		break;
	}
	return (a[0] % mod) * (a[1] % mod) % mod * (a[2] % mod) % mod;
}

inline LL Pow(LL base,LL k)
{
	LL ret = 1;
	for(;k;k>>=1,base=1ll*base*base % mod) if(k & 1) ret = 1ll * ret * base % mod;
	return ret;
}

LL Solve(LL m)
{
	if(m < ts) return pf[m];
	LL loc = n / m;
	if(f[loc] != -1) return f[loc];
	LL tmp = cal2(1,m);
	for(LL i=2,nxt,pre=1,tpre;i<=m;i=nxt+1)
	{
		nxt = m / (m / i);
		tmp = (tmp - ((tpre = cap2(nxt)) - pre) % mod * Solve(m / i) % mod) % mod;
		pre = tpre;
	}
	return f[loc] = (tmp + mod) % mod;
}

LL S(LL m)
{
	return cal2(1,m) * cal2(1,m) % mod;
}

int main()
{
	sieve();
	scanf("%lld",&n);
	memset(f,-1,sizeof f);
	LL ans = 0; 
	for(LL i=1,nxt,pre=0,rpre;i<=n;i=nxt+1)
	{
		nxt = n/(n/i);
		ans = (ans + ((rpre = Solve(nxt)) - Solve(i-1)) % mod * S(n/i) % mod) % mod;
		pre = rpre;
	}
	printf("%lld\n",(ans+mod) % mod);
}

51 nod 1227

Lcm(a,b)表示a和b的最小公倍数,A(n)表示Lcm(n,i)的平均数(1 <= i <= n),
例如:A(4) = (Lcm(1,4) + Lcm(2,4) + Lcm(3,4) + Lcm(4,4)) / 4 = (4 + 4 + 12 + 4) / 4 = 6。
F(a, b) = A(a) + A(a + 1) + … A(b)。(F(a,b) = ∑A(k), a <= k <= b)
例如:F(2, 4) = A(2) + A(3) + A(4) = 2 + 4 + 6 = 12。
给出a,b,计算F(a, b),由于结果可能很大,输出F(a, b) % 1000000007的结果即可。

a n s = ∑ 1 < = i < = j < = n i / g c d ( i , j ) = ∑ 1 < = d < = n ∑ 1 < = i < = j < = n / d [ g c d ( i , j ) = = 1 ] ∗ i = ∑ 1 < = d < = n ∑ 1 < = p < = n / d μ ( p ) ∗ p ∗ S ( n / d / p ) = ∑ 1 < = D < = n S ( n / D ) ∗ ∑ p ∣ D μ ( p ) ∗ p S ( n ) = ∑ 1 < = i < = n i ∗ ( n − i + 1 ) = ( n + 1 ) ∗ ( n + 1 ) ∗ n / 2 − n ∗ ( n + 1 ) ∗ ( 2 n + 1 ) / 6 = ( n + 2 ) ∗ ( n + 1 ) ∗ n 6 f ( n ) = ∑ p ∣ n μ ( p ) ∗ p f ∘ i d ( x ) = I \begin{aligned} ans =& \sum_{1<=i<=j<=n} i / gcd(i,j)\\ =&\sum_{1<=d<=n}\sum_{1<=i<=j<=n/d} [gcd(i,j)==1] * i\\ =&\sum_{1<=d<=n}\sum_{1<=p<=n/d} \mu(p) * p * S(n/d/p)\\ =&\sum_{1<=D<=n}S(n/D) * \sum_{p|D} \mu(p) * p\\ S(n) = &\sum_{1<=i<=n}i*(n-i+1) \\ =&(n+1) * (n+1) * n / 2 - n * (n+1) * (2n+1) / 6\\ =& \frac {(n+2) * (n+1) * n}{6}\\ f(n) = &\sum_{p|n} \mu(p) * p\\ f \circ &id (x)= I \end{aligned} ans====S(n)===f(n)=f1<=i<=j<=ni/gcd(i,j)1<=d<=n1<=i<=j<=n/d[gcd(i,j)==1]i1<=d<=n1<=p<=n/dμ(p)pS(n/d/p)1<=D<=nS(n/D)pDμ(p)p1<=i<=ni(ni+1)(n+1)(n+1)n/2n(n+1)(2n+1)/66(n+2)(n+1)npnμ(p)pid(x)=I

一个括号啊,我调了40min

#include<bits/stdc++.h>
#define LL long long
#define mod 1000000007
using namespace std;

LL a,b;
map<LL,int>mp;

#define ts 5000005
int mu[ts] , pr[ts / 8] , cnt_pr;
bool vis[ts];

void sieve()
{
	mu[1] = 1;
	for(int i=2;i<ts;i++)
	{
		if(!vis[i]) pr[cnt_pr++] = i , mu[i] = 1-i;
		for(int j=0;j<cnt_pr && pr[j] * i < ts;j++)
		{
			vis[i * pr[j]] = 1;
			if(i % pr[j] == 0)
			{
				mu[i * pr[j]] = mu[i];
				break;
			}
			mu[i * pr[j]] = (1ll * mu[i] * mu[pr[j]]) % mod;
		}	
	}
	for(int i=2;i<ts;i++) mu[i] = (mu[i] + mu[i-1]) % mod;
}

LL calc(LL a,LL b)
{
	LL c = a+b;
	b = b-a+1;
	if(c & 1) b/=2; else c/=2;
	return (c % mod) * (b % mod) % mod;
}

LL S(LL n)
{
	LL a[3] = {n,n+1,n+2};
	for(int i=0;i<3;i++) if(a[i] % 2 == 0) {a[i]/=2;break;}
	for(int i=0;i<3;i++) if(a[i] % 3 == 0) {a[i]/=3;break;}
	return (a[0] % mod) * (a[1] % mod) % mod * (a[2] % mod) % mod;
}

LL solve(LL n)
{
	if(n<ts) return mu[n];
	if(mp.count(n)) return mp[n];
	int tmp = n % mod;
	for(LL i=2,nxt;i<=n;i=nxt+1)
	{
		nxt = n/(n/i);
		tmp = (tmp - calc(i,nxt) * solve(n/i)) % mod;
	}
	return mp[n] = (tmp + mod) % mod;
}

LL As(LL n)
{
	LL ans = 0;
	for(LL i=1,nxt,pre=0,rpre;i<=n;i=nxt+1)
	{
		nxt = n / (n / i);
		ans = (ans + ((rpre = solve(nxt)) - pre) * S(n/i)) % mod;
		pre = rpre;
	}
	return ans;
}

int main()
{
	sieve();
	scanf("%lld%lld",&a,&b);
	printf("%lld\n",(As(b) - As(a-1) + mod) % mod);
}

51 nod 1222
A n s = ∑ 1 < = i < = j < = n [ i j g c d ( i , j ) < = n ] = ∑ 1 < = d < = n ∑ 1 < = i < = j < = n d [ i j d < = n ] ∗ [ g c d ( i , j ) = = 1 ] = ∑ 1 < = d < = n ∑ 1 < = p < = n d μ ( p ) ∑ 1 < = i < = j < = n d p [ i j d < = n p 2 ] = ∑ 1 < = p < = n μ ( p ) ∗ ∑ 1 < = d < = n , 1 < = i < = j < = n [ i j d < = n p 2 ] = n + ∑ 1 < = p < = n μ ( p ) ∗ ∑ 1 < = d , i , j < = n [ i j d < = n p 2 ] 2 \begin{aligned} Ans=&\sum_{1<=i<=j<=n}[\frac {ij}{gcd(i,j)} <= n ]\\ =&\sum_{1<=d<=n}\sum_{1<=i<=j<=\frac nd}[ijd<=n] * [gcd(i,j)==1]\\ =&\sum_{1<=d<=n}\sum_{1<=p<=\frac nd} \mu(p)\sum_{1<=i<=j<=\frac n{dp}}[ijd<=\frac n{p^2}]\\ =&\sum_{1<=p<=n}\mu(p) * \sum_{1<=d<=n,1<=i<=j<=n} [ijd<=\frac n{p^2}]\\ =&\frac{n + \sum_{1<=p<=n}\mu(p) * \sum_{1<=d,i,j<=n} [ijd<=\frac n{p^2}]}2 \end{aligned} Ans=====1<=i<=j<=n[gcd(i,j)ij<=n]1<=d<=n1<=i<=j<=dn[ijd<=n][gcd(i,j)==1]1<=d<=n1<=p<=dnμ(p)1<=i<=j<=dpn[ijd<=p2n]1<=p<=nμ(p)1<=d<=n,1<=i<=j<=n[ijd<=p2n]2n+1<=p<=nμ(p)1<=d,i,j<=n[ijd<=p2n]
可以for循环 O ( n 2 3 ) O(n^{\frac 23}) O(n32)统计。。。
AC Code:

#include<bits/stdc++.h>
#define LL long long
using namespace std;

#define ts 1000005
int pr[ts/8],cnt_pr,mu[ts];
bool vis[ts];

void sieve()
{
	mu[1] = 1;
	for(int i=2;i<ts;i++)
	{
		if(!vis[i]) pr[cnt_pr++] = i, mu[i] = -1;
		for(int j=0;pr[j] * i < ts;j++)
		{
			vis[i * pr[j]] = 1;
			if(i % pr[j] == 0) break;
			mu[i * pr[j]] = -mu[i];
		}
	}
}

LL solve(LL n)
{
	LL ans = 0;
	for(LL k=1;k*k<=n;k++)
		if(mu[k])
		{
			LL m = n / (k * k) , s = 0;
			for(LL i=1;i*i*i<=m;i++)
			{
				for(LL j=i+1;i*j*j<=m;j++)
					s+=(m / (i * j) - j) * 6 + 3;
				s+=(m/(i*i)-i)*3+1;
			}
			ans += mu[k] * s;
		}
	return (ans + n) / 2;
}

int main()
{
	sieve();
	LL a,b;
	scanf("%lld%lld",&a,&b);
	printf("%lld\n",solve(b) - solve(a-1));
}

SPOJ DIVCNT2 - Counting Divisors (square)
3个结论:
∑ p ∣ d μ ( p ) 2 = 2 ω ( p ) , ω ( p ) = p 的 质 因 子 个 数 \sum_{p|d}\mu(p)^2 = 2^{\omega\left(p\right)},\omega(p) = p的质因子个数 pdμ(p)2=2ω(p),ω(p)=p
∑ 1 < = i < = n μ ( p ) 2 = ∑ 1 < = i < = n μ [ i ] ∗ ⌊ n i 2 ⌋ \sum_{1<=i<=n}\mu(p)^2 = \sum_{1<=i<=\sqrt n}\mu[i] * \left \lfloor \frac n {i^2} \right \rfloor 1<=i<=nμ(p)2=1<=i<=n μ[i]i2n
∑ 1 < = i , j < = n [ i j < = n ] = ∑ 1 < = i < = n ⌊ n i ⌋ \sum_{1<=i,j<=n}[ij<=n] = \sum_{1<=i<=n}\left \lfloor \frac ni \right \rfloor 1<=i,j<=n[ij<=n]=1<=i<=nin
然后就完了?
AC Code:

#include<bits/stdc++.h>
#define LL long long
using namespace std;

#define ts 10000000
int mu[ts],pr[ts/8],cnt_pr,lp[ts],u[ts];
LL d[ts];
bool vis[ts];

void sieve()
{
	u[1] = mu[1] = d[1] = 1;
	for(int i=2;i<ts;i++)
	{
		if(!vis[i]) pr[cnt_pr++] = i , mu[i] = 1 , d[i] = 2 , lp[i] = 2 , u[i] = -1;
		for(int j=0;pr[j] * i < ts;j++)
		{
			vis[i * pr[j]] = 1;
			if(i % pr[j] == 0)
			{
				d[i * pr[j]] = d[i] / lp[i] * (lp[i * pr[j]] = lp[i] + 1);
				break;
			}
			u[i * pr[j]] = -u[i];
			mu[i * pr[j]] = mu[i];
			d[i * pr[j]] = d[i] * 2;
			lp[i * pr[j]] = 2;
		} 
		mu[i] += mu[i-1];
		d[i] += d[i-1];
	}
}

inline LL sum(LL n)
{
	if(n < ts) return mu[n];
	LL ans = 0;
	for(LL j=1;j*j<=n;j++)
		if(u[j])
			ans += u[j] * (n / (j * j));
	return ans;
}

inline LL sum2(LL n)
{
	if(n < ts) return d[n];
	LL ans = 0;
	for(LL i=1,nxt;i<=n;i=nxt+1)
		ans += ((nxt=(n/(n/i)))-i+1) * (n/i);
	return ans;
}

int main()
{
	sieve();
	int T;
	for(scanf("%d",&T);T--;)
	{
		LL n,ans=0;
		scanf("%lld",&n);
		for(LL i=1,nxt,pre=0,rpre;i<=n;i=nxt+1)
		{
			nxt = n / (n / i);
			ans += ((rpre = sum(nxt)) - pre) * sum2(n/i);
			pre = rpre;
		}
		printf("%lld\n",ans);
	}
}

51nod 1220 约数之和

d(k)表示k的所有约数的和。d(6) = 1 + 2 + 3 + 6 = 12。
定义S(N) = ∑1<=i<=N ∑1<=j<=N d(i*j)。
例如:S(3) = d(1) + d(2) + d(3) + d(2) + d(4) + d(6) + d(3) + d(6) + d(9) = 59,S(1000) = 563576517282。
给出正整数N,求S(N),由于结果可能会很大,输出Mod 1000000007(10^9 + 7)的结果。

∑ 1 < = i , j < = n d ( i j ) = ∑ 1 < = i , j < = n ∑ a ∣ i , b ∣ j [ g c d ( a , b ) = 1 ] = ∑ 1 < = i , j < = n ∑ p ∑ a ∣ i , b ∣ j μ [ p ] ∗ [ p ∣ g c d ( a , b ) ] = ∑ 1 < = i , j < = n ⌊ n i ⌋ ⌊ n j ⌋ ∗ ∑ p ∣ g c d ( i , j ) μ [ p ] = ∑ 1 < = p < = n μ ( p ) ∑ 1 < = i < = n p ⌊ n p i ⌋ ∑ 1 < = j < = n p ⌊ n p j ⌋ = ∑ 1 < = p < = n μ ( p ) G ( n p ) 2 G = I ∗ I I ∗ I ∗ μ = I \begin{aligned} \sum_{1<=i,j<=n}d(ij) =& \sum_{1<=i,j<=n}\sum_{a|i,b|j}[gcd(a,b) = 1]\\ =&\sum_{1<=i,j<=n}\sum_{p}\sum_{a|i,b|j} \mu[p] * [p | gcd(a,b)]\\ =&\sum_{1<=i,j<=n}\lfloor\frac ni\rfloor\lfloor\frac nj\rfloor*\sum_{p|gcd(i,j)} \mu[p]\\ =&\sum_{1<=p<=n}\mu(p) \sum_{1<=i<=\frac np}\lfloor\frac n{pi}\rfloor\sum_{1<=j<=\frac np}\lfloor\frac n{pj}\rfloor\\ =&\sum_{1<=p<=n}\mu(p) G(\frac np)^2\\ G = &I * I\\ I*I*\mu=&I \end{aligned} 1<=i,j<=nd(ij)=====G=IIμ=1<=i,j<=nai,bj[gcd(a,b)=1]1<=i,j<=npai,bjμ[p][pgcd(a,b)]1<=i,j<=ninjnpgcd(i,j)μ[p]1<=p<=nμ(p)1<=i<=pnpin1<=j<=pnpjn1<=p<=nμ(p)G(pn)2III
这是约数个数之和,BZOJ 4176 Lucas的数论。
真是个悲情的故事,还是放一下代码吧。
UPD:放个结论: σ k ( i j ) = ∑ a ∣ i , b ∣ j [ ( a , b ) = 1 ] ( a j b ) k \sigma_k(ij) = \sum_{a|i,b|j} [(a,b)=1](\frac {aj}b)^k σk(ij)=ai,bj[(a,b)=1](baj)k
AC Code:

#include<bits/stdc++.h>
#define LL long long
#define mod 1000000007
using namespace std;

#define ts 1000006
int mu[ts],lp[ts],pr[ts],cnt_pr;
LL d[ts];
bool vis[ts];

void sieve()
{
	mu[1] = d[1] = lp[1] = 1;
	for(int i=2;i<ts;i++)
	{
		if(!vis[i]) pr[cnt_pr++] = i , d[i] = lp[i] = 2 , mu[i] = -1;
		for(int j=0;pr[j] * i < ts;j++)
		{
			vis[i * pr[j]] = 1;
			if(i % pr[j] == 0)
			{
				d[i * pr[j]] = d[i] / lp[i] * (lp[i * pr[j]] = lp[i] + 1);
				break;
			}
			d[i * pr[j]] = d[i] * 2;
			mu[i * pr[j]] = -mu[i];
			lp[i * pr[j]] = 2;
		}
		d[i] = (d[i] + d[i-1]) % mod;
		mu[i] = (mu[i] + mu[i-1]) % mod;
	}
}

map<LL,int>mmu,md;
LL smu(LL n)
{
	if(n < ts) return mu[n];
	if(mmu.count(n)) return mmu[n];
	int tmp = 1;
	for(LL i=2,nxt;i<=n;i=nxt+1)
	{
		nxt = n / (n / i);
		tmp = (tmp - (nxt - i + 1) % mod * smu(n/i)) % mod;
	}
	return mmu[n] = (tmp + mod)%mod;
}

LL sd(LL n)
{
	if(n < ts) return d[n];
	if(md.count(n)) return md[n];
	int tmp = n % mod;
	for(LL i=2,nxt,pre=1,rpre;i<=n;i=nxt+1)
	{
		nxt = n / (n / i);
		tmp = (tmp - ((rpre = smu(nxt)) - pre) * sd(n/i)) % mod;
		pre = rpre;
	}
	return md[n] = tmp;
}

int main()
{
	sieve();
	LL n,ans=0;
	scanf("%lld",&n);
	for(LL i=1,nxt,pre=0,rpre;i<=n;i=nxt+1)
	{
		nxt = n / (n / i);
		ans = (ans + ((rpre = smu(nxt)) - pre) * sd(n/i) %mod *sd(n/i)) % mod;
		pre = rpre;
	}
	printf("%lld\n",(ans+mod)%mod);
}

其实对于约数之和也有一个类似的推法。
∑ 1 < = i , j < = n d ( i j ) = ∑ 1 < = i , j < = n ∑ a ∣ i , b ∣ j a j [ g c d ( a , b ) = = 1 ] b = ∑ 1 < = i , j < = n ∑ a ∣ i , b ∣ j a j ∑ p ∣ g c d ( a , b ) μ ( p ) b 先枚举a和b = ∑ 1 < = a , b < = n a ∗ ⌊ n a ⌋ ∗ ( b + b ⌊ n b ⌋ ) ∗ ⌊ n b ⌋ 2 ∑ p ∣ g c d ( a , b ) μ ( p ) b = ∑ 1 < = a , b < = n a ⌊ n a ⌋ ∗ ( 1 + ⌊ n b ⌋ ) ∗ ⌊ n b ⌋ 2 ∗ ∑ p ∣ g c d ( a , b ) μ ( p ) 先枚举p再枚举gcd S ( n ) = ( 1 + n ) ∗ n 2 = ∑ 1 < = p < = n μ ( p ) ∑ 1 < = a < = n p a p ⌊ n a p ⌋ ∗ ∑ 1 < = b < = n p S ( b ) = ∑ 1 < = p < = n μ ( p ) p ( ∑ 1 < = a < = n p a ⌊ n a p ⌋ ) 2 = ∑ 1 < = p < = n μ ( p ) p ( ∑ 1 < = a < = n p σ ( a ) ) 2 \begin{aligned} \sum_{1<=i,j<=n} d(ij) =& \sum_{1<=i,j<=n}\sum_{a|i,b|j} \frac {aj[gcd(a,b)==1]}{b}\\ =&\sum_{1<=i,j<=n}\sum_{a|i,b|j} \frac {aj \sum_{p|gcd(a,b)}\mu(p)}{b}\\ &\text{先枚举a和b}\\ =&\sum_{1<=a,b<=n} \frac{\frac {a * \lfloor \frac na \rfloor * (b + b\lfloor \frac nb \rfloor) * \lfloor \frac nb \rfloor } 2\sum_{p|gcd(a,b)}\mu(p)}{b}\\ =&\sum_{1<=a,b<=n} \frac{a\lfloor \frac na \rfloor * (1+\lfloor \frac nb \rfloor) * \lfloor \frac nb \rfloor}{2} * \sum_{p|gcd(a,b)}\mu(p)\\ &\text{先枚举p再枚举gcd}\\ &S(n) = \frac {(1 + n) * n}2\\ =&\sum_{1<=p<=n} \mu(p) \sum_{1<=a<=\frac np} ap\lfloor \frac n{ap} \rfloor * \sum_{1<=b<=\frac np} S(b)\\ =&\sum_{1<=p<=n} \mu(p) p\left(\sum_{1<=a<=\frac np} a\lfloor \frac n{ap} \rfloor \right)^2\\ =&\sum_{1<=p<=n} \mu(p) p\left(\sum_{1<=a<=\frac np} \sigma(a) \right)^2 \end{aligned} 1<=i,j<=nd(ij)=======1<=i,j<=nai,bjbaj[gcd(a,b)==1]1<=i,j<=nai,bjbajpgcd(a,b)μ(p)先枚举ab1<=a,b<=nb2aan(b+bbn)bnpgcd(a,b)μ(p)1<=a,b<=n2aan(1+bn)bnpgcd(a,b)μ(p)先枚举p再枚举gcdS(n)=2(1+n)n1<=p<=nμ(p)1<=a<=pnapapn1<=b<=pnS(b)1<=p<=nμ(p)p1<=a<=pnaapn21<=p<=nμ(p)p1<=a<=pnσ(a)2
后面那个是约数和的前缀和的平方,为 i d ∘ I id\circ I idI 卷一个 μ \mu μ就行。
前面那个卷一个 i d id id就行
那么就可以筛了。

AC Code:

#include<bits/stdc++.h>
#define LL long long
#define mod 1000000007
using namespace std;

#define ts 5000005
int pr[ts],cnt_pr,mup[ts],sig[ts],mu[ts];
bool vis[ts]; 

void sieve()
{
	mup[1] = 1 , sig[1] = 1 , mu[1] = 1;
	for(int i=2;i<ts;i++)
	{
		if(!vis[i]) pr[cnt_pr++] = i , mu[i] = -1 , sig[i] = i+1;
		for(int j=0;pr[j] * i < ts;j++)
		{
			vis[i * pr[j]] = 1;
			if(i % pr[j] == 0)
			{ 
				sig[i * pr[j]] = (1ll * sig[i] * (pr[j] + 1) - 1ll * sig[i / pr[j]] * pr[j]) % mod;
				break;
			}
			mu[i * pr[j]] = -mu[i];
			sig[i * pr[j]] = 1ll * sig[i] * sig[pr[j]] % mod;
		}
	}
	for(int i=2;i<ts;i++)
		mup[i] = (1ll * mu[i] * i + mup[i-1]) % mod,
		mu[i] = mu[i] + mu[i-1],
		sig[i] = (sig[i] + sig[i-1]) % mod;
}

LL calc2(LL n)
{
	static int inv2 = (mod+1) / 2;
	return n % mod * ((n+1) % mod) % mod * inv2 % mod;
}

map<LL,LL>mmup,msig,mmu;

LL calmu(LL n)
{
	if(n < ts) return mu[n];
	if(mmu.count(n)) return mmu[n];
	int tmp = 1;
	for(LL i=2,nxt;i<=n;i=nxt+1)
	{
		nxt = n / (n / i);
		tmp = (tmp - (nxt - i + 1) % mod * calmu(n/i)) % mod;
	}
	return mmu[n] = tmp;
}

LL calmup(LL n)
{
	if(n < ts) return mup[n];
	if(mmup.count(n)) return mmup[n];
	int tmp = 1;
	for(LL i=2,nxt;i<=n;i=nxt+1)
	{
		nxt = n / (n / i);
		tmp = (tmp - (calc2(nxt) - calc2(i-1)) * calmup(n/i)) % mod;
	}
	return mmup[n] = tmp;
}

LL calsig(LL n)
{
	if(n < ts) return sig[n];
	if(msig.count(n)) return msig[n];
	int tmp = calc2(n);
	for(LL i=2,nxt;i<=n;i=nxt+1)
	{
		nxt = n / (n / i);
		tmp = (tmp - (calmu(nxt) - calmu(i-1)) * calsig(n/i)) % mod;
	}
	return msig[n] = tmp;
}

inline LL sqr(LL a)
{
	return a * a % mod;
}

int main()
{
	sieve();
	LL n;
	scanf("%lld",&n);
	int ans = 0;
	for(LL i=1,nxt;i<=n;i=nxt+1)
	{
		nxt = n/(n/i);
		ans = (ans + 1ll * (calmup(nxt) - calmup(i-1)) * sqr(calsig(n/i))) % mod;
	}
	printf("%d\n",(ans+mod) % mod);
}

打完之后发现自己好智障啊,大于 n 2 3 n^{\frac 23} n32的可以直接
∑ 1 < = i < = n σ ( i ) = ∑ 1 < = i < = n ⌊ n i ⌋ \sum_{1<=i<=n}\sigma(i) = \sum_{1<=i<=n}\lfloor \frac ni \rfloor 1<=i<=nσ(i)=1<=i<=nin
然后分块优化做。。。。。。复杂度一样,我还多筛了一个 μ \mu μ

51nod 1584加权约数和

去年的 tangjz 非常喜欢做数论题,但是一年以后的 tangjz 却不那么会做了。
在整理以前的试题时,他发现了这样一道题目:“求 ∑σ(i) ,其中 1≤i≤N , σ(i) 表示 i 的约数之和。”
现在他长大了,题目也变难了,所以麻烦你来帮他解决一道数论题吧。
他需要你求如下表达式的值:
∑ i = 1 N ∑ j = 1 N m a x ( i , j ) ⋅ σ ( i ⋅ j ) ∑^N_{i=1}∑^N_{j=1}max(i,j)⋅σ(i⋅j) i=1Nj=1Nmax(i,j)σ(ij)
其中 max(i,j) 表示 i 和 j 里的最大值, σ(i⋅j) 表示 i⋅j 的约数之和。
例如当 N=2 的时候,由 σ(1)=1,σ(2)=1+2=3,σ(4)=1+2+4=7 可知,答案应为 1⋅σ(1⋅1)+2⋅σ(1⋅2)+2⋅σ(2⋅1)+2⋅σ(2⋅2)=27 。
他发现答案有点大,所以你只需要告诉他答案模 1000000007 的值即可。

为啥我明知道它就是几个题套起来但是我就是不敢打。
A = ∑ i = 1 n i ∑ j = 1 i σ ( i j ) , B = ∑ i = 1 n i σ ( i 2 ) A n s = 2 A − B A = ∑ i = 1 n i ∑ j = 1 i ∑ a ∣ i , b ∣ j a j [ ( a , b ) = 1 ] b = ∑ 1 < = a , b < = n ∑ i = 1 n a i a ∑ j = 1 i a b a j b b [ ( a , b ) = = 1 ] = ∑ 1 < = a , b < = n [ ( a , b ) = 1 ] a 2 ∑ i = 1 n a i ∑ j = 1 i a b j 发现层层嵌套太复杂,彻底打散,寻找适合化简的性质 = ∑ 1 < = a , b , i , j < = n a 2 i j [ ( a , b ) = 1 ] [ i a > = j b ] [ i a < = n ] 之前方法的病就在ia>=jb不好利用上,于是枚举ia和jb = ∑ 1 < = a i < = n a 2 i ∑ 1 < = j b < = a i j [ ( a , b ) = 1 ] 实际上的变量是ia和bj,于是i和j得枚举 = ∑ 1 < = a i < = n a i ∑ i ∣ a i i ∑ 1 < = j b < = a i ∑ j ∣ j b j = ∑ 1 < = a i < = n a i σ ( a i ) ∑ 1 < = j b < = a i σ ( j b ) 明显是积性函数,可以线性筛 \begin{aligned} &A = \sum_{i=1}^ni\sum_{j=1}^i \sigma(ij) , B = \sum_{i=1}^ni\sigma(i^2)\\ &Ans = 2A - B\\ &A=\sum_{i=1}^ni\sum_{j=1}^i\sum_{a|i,b|j}\frac {aj[(a,b)=1]}b\\ &=\sum_{1<=a,b<=n}\sum_{i=1}^{\frac na} ia\sum_{j=1}^{\frac {ia}b} \frac{ajb}b[(a,b)==1]\\ &=\sum_{1<=a,b<=n}[(a,b)=1]a^2\sum_{i=1}^{\frac na}i\sum_{j=1}^{\frac {ia}b}j\\ &\text{发现层层嵌套太复杂,彻底打散,寻找适合化简的性质}\\ &=\sum_{1<=a,b,i,j<=n}a^2ij[(a,b)=1][ia>=jb][ia<=n]\\ &\text{之前方法的病就在ia>=jb不好利用上,于是枚举ia和jb}\\ &=\sum_{1<=ai<=n}a^2i\sum_{1<=jb<=ai}j[(a,b)=1]\\ &\text{实际上的变量是ia和bj,于是i和j得枚举}\\ &=\sum_{1<=ai<=n}ai\sum_{i|ai}i\sum_{1<=jb<=ai}\sum_{j|jb}j\\ &=\sum_{1<=ai<=n}ai\sigma(ai)\sum_{1<=jb<=ai}\sigma(jb)\\ &\text{明显是积性函数,可以线性筛} \end{aligned} A=i=1nij=1iσ(ij),B=i=1niσ(i2)Ans=2ABA=i=1nij=1iai,bjbaj[(a,b)=1]=1<=a,b<=ni=1aniaj=1biabajb[(a,b)==1]=1<=a,b<=n[(a,b)=1]a2i=1anij=1biaj发现层层嵌套太复杂,彻底打散,寻找适合化简的性质=1<=a,b,i,j<=na2ij[(a,b)=1][ia>=jb][ia<=n]之前方法的病就在ia>=jb不好利用上,于是枚举iajb=1<=ai<=na2i1<=jb<=aij[(a,b)=1]实际上的变量是iabj,于是ij得枚举=1<=ai<=naiiaii1<=jb<=aijjbj=1<=ai<=naiσ(ai)1<=jb<=aiσ(jb)明显是积性函数,可以线性筛
B也用差不多的方法就行,这题只需要线性筛,然后再离线一波就可以做到 O ( n l o g n ) O(nlogn) O(nlogn)预处理, O ( 1 ) O(1) O(1)回答。

AC Code:

#include<bits/stdc++.h>
#define mod 1000000007
#define maxn 1000005
#define LL long long
using namespace std;

int mu[maxn],pr[maxn/8]
,cnt_pr,d[maxn],sumuf[maxn],sumsig[maxn],sumasig[maxn],sumasigf[maxn];
bool vis[maxn];
int lim[maxn],c[maxn];
inline bool cmp(const int &u,const int &v){ return lim[u] < lim[v]; }
int add[maxn],ret[maxn];
void sieve()
{
	mu[1] = 1 , d[1] = 1;
	for(int i=2;i<maxn;i++)
	{
		if(!vis[i]) pr[cnt_pr++] = i , mu[i] = -1 , d[i] = 1 + i;
		for(int j=0;pr[j]*i<maxn;j++)
		{
			vis[i * pr[j]] = 1;
			if(i % pr[j] == 0)
			{
				d[i * pr[j]] = (1ll * d[i] * (pr[j]+1) - 1ll * d[i/pr[j]] * pr[j]) % mod;
				break;
			}
			mu[i * pr[j]] = -mu[i];
			d[i * pr[j]] = 1ll * d[i] * d[pr[j]] % mod;
		}
	}
	for(int i=1;i<maxn;i++)
		sumuf[i] = (1ll * mu[i] * i * i) % mod,
		sumsig[i] = (sumsig[i-1] + d[i]) % mod,
		sumasig[i] = 1ll * d[i] * i % mod * (2ll * sumsig[i] - d[i]) % mod;
	for(int i=1;i<maxn;i++)
		for(int j=1;i*j<maxn;j++)
			add[i*j]=(add[i*j]+1ll*sumuf[i]*sumasig[j]) % mod;
}
int main()
{
	int T,ans=0;
	scanf("%d",&T);
	for(int i=0;i<T;i++) scanf("%d",&lim[i]),c[i]=i;
	sort(c,c+T,cmp);
	sieve();
	
	for(int i=0,j=1;i<T;i++)
	{
		for(;j<=lim[c[i]];j++) ans=(ans+add[j])%mod;
		ret[c[i]] = ans;
	}
	for(int i=0;i<T;i++) printf("Case #%d: %d\n",i+1,(ret[i]+mod)%mod);
	
}

(我居然都可以rank1,。。。。。。)
这个题告诉我们,杜教筛最重要的不是把式子化到有多简,而是时刻判断当前式子能否完成问题,必要时让步,用最暴力的办法写式子反而会有所发现,还有就是对于积性函数要敏感,线性筛是很强大的。。。。。。

到现在我们还可以发现一个事情:
∑ a ∣ i , b ∣ j a j b [ ( a , b ) = 1 ] = ∑ p ∣ ( i , j ) μ ( p ) p ∗ σ ( i p ) ∗ σ ( j p ) \sum_{a|i,b|j}\frac {aj}b[(a,b)=1] = \sum_{p|(i,j)}\mu(p)p*\sigma(\frac ip)*\sigma(\frac jp) ai,bjbaj[(a,b)=1]=p(i,j)μ(p)pσ(pi)σ(pj)

ZOJ Problem Set - 3881
From ABC Conjecture
主要是变形神。
r a d ( n ) = ∏ i = 1 k P i , w h e r e   n = ∏ i = 1 k P i a i f ( n ) = r a d ( n ) ∗ φ ( n r a d ( n ) ) g = I ∘ f c a l c   H ( n ) = ∑ 1 < = i < = n g ( i ) \begin{aligned} &rad(n) = \prod_{i=1}^{k}Pi,where \ n = \prod_{i=1}^kPi^{ai}\\ &f(n)=rad(n) * \varphi(\frac n{rad(n)})\\ &g = I \circ f\\ &calc \ H(n) = \sum_{1<=i<=n}g(i) \end{aligned} rad(n)=i=1kPi,where n=i=1kPiaif(n)=rad(n)φ(rad(n)n)g=Ifcalc H(n)=1<=i<=ng(i)
首先证明 f ( n ) 是 积 性 函 数 f(n)是积性函数 f(n)(显然啊)
然后就是套路了。
∑ i ∣ n f ( i ) = ∑ i ∣ n ∏ j = 1 k f ( P j a j )   w h e r e   ∏ j = 1 k P j a j = i = ∏ j = 1 k ∑ i = 0 a j f ( P j i ) \sum_{i|n}f(i) = \sum_{i|n} \prod_{j=1}^kf(Pj^{aj}) \ where \ \prod_{j=1}^k Pj^{aj} = i\\ =\prod _{j=1}^k \sum_{i=0}^{aj}f(Pj^{i}) inf(i)=inj=1kf(Pjaj) where j=1kPjaj=i=j=1ki=0ajf(Pji)
这个例子告诉我们和式和积式也是可以交换枚举顺序的。
然后将 f ( x ) f(x) f(x)带入就可以用高中生(小学生)的等比数列求和得到
g ( n ) = ∏ j = 1 k P j a j + 1   w h e r e   n = ∏ j = 1 k P j a j g(n) = \prod_{j=1}^kPj^{aj}+1\ where \ n = \prod_{j=1}^k Pj^{aj} g(n)=j=1kPjaj+1 where n=j=1kPjaj
这个式子我们可以高级(套路)一点:
g ( n ) = ∑ j ∣ n [ ( j , n j ) = 1 ] j g(n) = \sum_{j|n}[(j,\frac nj)=1]j g(n)=jn[(j,jn)=1]j
出现gcd就莫比乌斯反演:
g ( n ) = ∑ j ∣ n j ∑ p ∣ ( j , n j ) μ ( p ) = ∑ p ∣ n μ ( p ) ∑ j ∣ n p , k ∣ n p [ p j ∗ p k = n ] j p = ∑ p 2 ∣ n μ ( p ) p ∑ j , k [ j ∗ k = n p 2 ] j = ∑ p 2 ∣ n μ ( p ) p σ ( n p 2 ) g(n) = \sum_{j|n}j\sum_{p|(j,\frac nj)}\mu(p) =\sum_{p|n}\mu(p)\sum_{j|\frac np,k|\frac np}[pj * pk = n]jp\\ =\sum_{p^2|n}\mu(p)p\sum_{j,k}[j*k = \frac n{p^2}]j\\ =\sum_{p^2|n}\mu(p)p\sigma(\frac n{p^2}) g(n)=jnjp(j,jn)μ(p)=pnμ(p)jpn,kpn[pjpk=n]jp=p2nμ(p)pj,k[jk=p2n]j=p2nμ(p)pσ(p2n)
然后就随便搞了。
H ( n ) = ∑ i = 1 n ∑ p 2 ∣ i μ ( p ) p σ ( i p 2 ) = ∑ p = 1 n μ ( p ) p ∑ i = 1 n p 2 σ ( i ) = ∑ p = 1 n μ ( p ) p S ( n p 2 ) H(n) = \sum_{i=1}^n\sum_{p^2|i}\mu(p)p\sigma(\frac i{p^2})\\ =\sum_{p=1}^n\mu(p)p\sum_{i=1}^{\frac n{p^2}}\sigma(i)\\ =\sum_{p=1}^{\sqrt n}\mu(p)pS(\frac n{p^2}) H(n)=i=1np2iμ(p)pσ(p2i)=p=1nμ(p)pi=1p2nσ(i)=p=1n μ(p)pS(p2n)
后面那个是约数前缀和,可以 O ( n ) O(\sqrt n) O(n )
前面那个只需要枚举到 n \sqrt n n
复杂度可以积分估计:
∫ 1 n n x 2 d x = n g ( x )   w h e r e   g ( x ) = ln ⁡ x \large\int_{1}^{\sqrt n}\sqrt \frac{n}{x^2}dx=\sqrt n g(\sqrt x) \ where \ g(x) = \ln x 1n x2n dx=n g(x ) where g(x)=lnx
O ( n ln ⁡ n ) O(\sqrt n \ln n) O(n lnn)
AC Code:

#include<bits/stdc++.h>
#define maxn 1000006
#define mod 1000000009
#define LL long long
#define inv2 (mod+1)/2
using namespace std;

int mu[maxn],pr[maxn],cnt_pr;
bool vis[maxn];
void sieve()
{
	mu[1] = 1;
	for(int i=2;i<maxn;i++)
	{
		if(!vis[i]) pr[cnt_pr++] = i, mu[i] = -1;
		for(int j=0;pr[j]*i<maxn;j++)
		{
			vis[i*pr[j]] = 1;
			if(i % pr[j] == 0) break;
			mu[i * pr[j]] = -mu[i];
		}
	}
}

int S(LL n)
{
	int ans = 0;
	for(LL i=1,nxt;i<=n;i=nxt+1)
	{
		nxt = n / (n / i);
		ans = (ans + (nxt+i) % mod * ((nxt - i + 1)%mod) % mod * (n/i) % mod) % mod;
	}
	return (1ll * ans * inv2)%mod;
}

int main()
{
	sieve();
	LL N;
	for(;~scanf("%lld",&N);)
	{
		int ans = 0;
		for(int i=1;1ll*i*i<=N;i++)
			ans =(ans + 1ll * mu[i] * i * S(N / (1ll * i * i))) % mod;
		printf("%d\n",(ans+mod)%mod);
	}
}

BZOJ 3512 DZY loves Math IV
给定n,m, ∑ i = 1 n ∑ j = 1 m φ ( i j ) \sum_{i=1}^n\sum_{j=1}^m\varphi (ij) i=1nj=1mφ(ij)求 模10^9+7的值。
n < = 1 0 5 , m < = 1 0 9 n<=10^5,m<=10^9 n<=105,m<=109
这个
充分告诉我们 φ \varphi φ的性质可以创造奇迹。
首先有 φ ( i j ) = φ ( i ) φ ( j ) d φ ( d ) \varphi(ij) = \frac {\varphi(i)\varphi(j)d}{\varphi(d)} φ(ij)=φ(d)φ(i)φ(j)d
然后发现做不下去。。。。。。

发现 n < = 1 0 5 n<=10^5 n<=105
可以考虑枚举一维x
接下来就只需要求 f ( x , m ) = ∑ i = 1 m φ ( x i ) f(x,m) = \sum_{i=1}^m\varphi(xi) f(x,m)=i=1mφ(xi)
但是发现好像还是不好求。
考虑欧拉函数的性质,如果 x x x是无平方因子数。
f ( x , m ) = ∑ i = 1 m φ ( x ) φ ( i ) ( i , x ) φ ( ( i , x ) ) = ∑ i = 1 m φ ( x ( i , x ) ) φ ( i ) ( i , x ) f(x,m)=\sum_{i=1}^m\frac {\varphi(x)\varphi(i)(i,x)}{\varphi((i,x))}=\sum_{i=1}^m\varphi(\frac x{(i,x)})\varphi(i)(i,x) f(x,m)=i=1mφ((i,x))φ(x)φ(i)(i,x)=i=1mφ((i,x)x)φ(i)(i,x)
然后就像用 ∑ p ∣ g c d μ ( p ) = [ g c d = = 1 ] \sum_{p|gcd}\mu(p) = [gcd==1] pgcdμ(p)=[gcd==1]一样用 ∑ p ∣ g c d φ ( p ) = g c d \sum_{p|gcd}\varphi(p) = gcd pgcdφ(p)=gcd
来将和gcd有关的式子化为和式然后再调换求和顺序最终转化为枚举约数:
f ( x , m ) = ∑ i = 1 m φ ( x d ) φ ( i ) ∑ p ∣ d φ ( p ) f(x,m)=\sum_{i=1}^m\varphi(\frac xd)\varphi(i)\sum_{p|d}\varphi(p)\\ f(x,m)=i=1mφ(dx)φ(i)pdφ(p)
貌似已经山穷水尽了?毕竟还有一个gcd呢。
发现 p p p x d \frac xd dx是互质的然后就很简单了。
f ( x , m ) = ∑ i = 1 m φ ( i ) ∑ p ∣ d φ ( x p d ) = ∑ i = 1 m φ ( i ) ∑ p ∣ d φ ( x p ) ! ! ! = ∑ p ∣ x φ ( x p ) ∑ i = 1 m p φ ( i p ) = ∑ p ∣ x φ ( x p ) f ( p , m p ) f(x,m)=\sum_{i=1}^m\varphi(i)\sum_{p|d} \varphi(\frac {xp}d)\\ =\sum_{i=1}^m\varphi(i)\sum_{p|d}\varphi(\frac xp)!!!\\ =\sum_{p|x}\varphi(\frac xp)\sum_{i=1}^{\frac mp}\varphi(ip) =\sum_{p|x}\varphi(\frac xp)f(p,\frac mp) f(x,m)=i=1mφ(i)pdφ(dxp)=i=1mφ(i)pdφ(px)!!!=pxφ(px)i=1pmφ(ip)=pxφ(px)f(p,pm)
然后对于非无平方因子数,把多了的质因子提出来就行了。
这里面的 φ \varphi φ技巧好多啊。
1: ∑ p ∣ g c d φ ( p ) = g c d \sum_{p|gcd}\varphi(p) = gcd pgcdφ(p)=gcd
2:积性函数性质
3:提多余质因子,提成无平方因子数
4: φ ( x y ) = φ ( x ) φ ( y ) ( x , y ) φ ( ( x , y ) ) \varphi(xy)=\frac {\varphi(x)\varphi(y)(x,y)}{\varphi((x,y))} φ(xy)=φ((x,y))φ(x)φ(y)(x,y)
然后。。。。。。
这差不多就是 φ \varphi φ的套路吧。
AC Code:

#include<bits/stdc++.h>
#define maxn 100005
#define LL long long
#define mod 1000000007
using namespace std;

vector<int>di[maxn];
#define ts 5000005
int phi[ts],sphi[ts],pr[ts/8],cnt_pr,isd[ts];
bool vis[ts];
void sieve()
{
	phi[1] = 1 , isd[1] = 1 , sphi[1] = 1;
	for(int i=2;i<ts;i++)
	{
	 	if(!vis[i]) pr[cnt_pr++] = i , phi[i] = i-1 , isd[i] = i;
	 	for(int j=0;pr[j] * i < ts ; j++)
	 	{
	 		vis[i * pr[j]] = 1;
	 		if(i % pr[j] == 0)
			{
				phi[i * pr[j]] = phi[i] * pr[j];
				isd[i * pr[j]] = isd[i];
				break; 
			}	
			isd[i * pr[j]] = isd[i] * pr[j];
			phi[i * pr[j]] =  phi[i] * pr[j]- phi[i];
		}
		sphi[i] = (phi[i] + sphi[i-1]) % mod;
	} 	
	for(int i=1;i<maxn;i++)
		for(int j=i;j<maxn;j+=i)
			di[j].push_back(i);
}

map<LL,int>mp,st[maxn];
int Phi(LL n)
{
	if(n < ts) return sphi[n];
	if(mp.count(n)) return mp[n];
	static int inv2 = (mod+1) / 2;
	int tmp = 1ll * (n % mod) * ((n+1) % mod) % mod * inv2 % mod;
	for(LL i=2,nxt;i<=n;i=nxt+1)
	{
		nxt = n / (n / i);
		tmp = (tmp - 1ll * (nxt - i + 1) % mod * Phi(n / i)) % mod;
	}
	return mp[n] = tmp;
}

LL n , m;
int S(LL n,LL m)
{
	if(n == 1) return Phi(m);
	if(st[n].count(m)) return st[n][m];
	int w = isd[n] , y = n / w;
	int tmp = 0;
	for(int i=0,siz=di[w].size();i<siz && di[w][i]<=m;i++)
		tmp =(tmp + 1ll * phi[w/di[w][i]] * S(di[w][i],m/di[w][i])) % mod;
	return st[n][m] = 1ll * tmp * y % mod;
}

int main()
{
	sieve();
	scanf("%lld%lld",&n,&m);
	int ans = 0;
	for(int i=1;i<=n;i++) 
		ans = (ans + S(i , m)) % mod;
	printf("%d\n",(ans+mod)%mod);
}

ZOJ 5340 - The Sum of Unitary Totient(常规积性函数求和,数据组数较多,只可分段打表)
SPOJ DIVCNT3 - Counting Divisors (cube)(常规积性函数求和,注意代码长度限制,不可打表)
51Nod 1575 - Gcd and Lcm(常规积性函数求和,可分段打表)
51Nod 1847 - 奇怪的数学题(非常规积性函数求和,综合题,可分段打表)
最后这4个实在是找不到杜教筛的题解。
准备转Min_25/洲阁筛了,撑不住了。。。。。。。
大家请不欢而散吧。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值