1. 程式人生 > 實用技巧 >Spring-07-AOP

Spring-07-AOP

積性函式指對於所有互質的整數a和b有性質f(ab)=f(a)f(b)的數論函式。

狄利克雷卷積

\((f * g)(n)=\sum_{d \mid n} f(d) g\left(\frac{n}{d}\right)\)
性質1:

兩個積性函式的狄利克雷卷積還是積性函式。

證明:感性理解一下,兩個互質的下標乘起來,相當於兩個和式乘起來,因為是互質的相當於列舉到了乘積的所有約數,因為和式裡面都是積性函式所以乘起來也是積性函式。

性質2:

三大運算規律:結合律,交換律,分配律。

常見運算

除數函式: \(\sigma_{x}(n)=\sum_{d \mid n} d^{x}\)
約數個數函式: \(d(n)=\sum_{d \mid n} 1\)

約數和函式: \(\sigma(n)=\sum_{d n} d\)
元函式: \(e(n)=[n=1](\{1,0,0,0,0 \ldots . . .\})\)
恆等函式: \(I(n)=1(\{1,1,1,1,1 \ldots \ldots\})\)
單位函式: \(\varepsilon(n)=n(\{1,2,3,4,5 \ldots \ldots\})\)
尤拉函式: \(\phi(n)\) 莫比烏斯函式: \(\mu(n)\)

\(\mu(i)=\left\{\begin{array}{c}1, i=1 \\ (-1)^{k}, i=p 1 * p 2 * \ldots * p k \\ 0, \text { rest }\end{array}\right.\)

\(\varepsilon=\phi * I \Leftrightarrow n=\sum_{d \mid n} \phi(d)\)
\(d=I * I \Leftrightarrow d(n)=\sum_{d \mid n} 1\)
\(\sigma=\varepsilon * I \Leftrightarrow \sigma(n)=\sum_{d \mid n} d\)
\(e=I * \mu \Leftrightarrow[n==1]=\sum_{d \mid n} \mu(d)\)
\(\phi=\varepsilon * \mu \Leftrightarrow \phi(n) \sum_{d \mid n} \mu(d) * \frac{n}{d}\)

莫比烏斯反演

\[g(n)=\sum_{d \mid n} f(d) \]

\[f(n)=\sum_{d |n} \mu(d) g\left(\frac{n}{d}\right) \]

證明:這裡需要用到前面提到的性質: \(\mu * I=\epsilon\)
給出的條件等價於 \(g=f * I\)
所以 \(g * \mu=f * I * \mu=f * \epsilon=f\)\(g * \mu=f\) 即 結論

杜教篩

\(g(1) S(n)=\sum_{i=1}^{n}(f * g)(i)-\sum_{i=2}^{n} g(i) S\left(\left\lfloor\frac{n}{i}\right\rfloor\right)\)
求解\(S(n)\),可以設定\(f\)\(g\)
\((1)\mu(n)\)字首和
考慮到莫比烏斯函式的性質 \(\mu * I=\epsilon,\) 自然想到取 \(f=\mu, g=I, f * g=\epsilon\)

\((2)\varphi\) 的字首和
考慮到 \(\varphi\) 的性質 \(\varphi * I=i d,\)\(f=\varphi, g=I, f * g=i d\)

(3)\(\sum_{i=1}^{n} \varphi(i) \cdot i\)
\(f=\varphi \cdot i d, g=i d,\) 考慮迪利克雷卷積的形式得到 \((f * g)(n)=\sum_{d \mid n}(\varphi(d) \cdot d) \cdot\left(\frac{n}{d}\right)=\)
\(n \sum_{d \mid n} \varphi(d)=n^{2}\)
\((f * g)(i)=i^{2}\)
這樣就可以快速求得 \((f * g)(i)\) 的字首和 \(\frac{n(n+1)(2 n+1)}{6}\)

例題

const int N=1000009;
const int mod=1e9+7;
int pre[N];
int phi[N];
int vis[N];
int prime[N];
int _2,_6;
unordered_map<int,int>mp;
void init()
{
	phi[1]=1;
	int cnt=0;
	for(int i=2;i<=N;i++)
	{
		if(!vis[i])
		{
			prime[++cnt]=i;
			phi[i]=i-1;
		}
		for(int j=1;j<=cnt&&prime[j]*i<=N;j++)
		{
			vis[prime[j]*i]=1;
			if(i%prime[j]==0)
			{
				phi[i*prime[j]]=phi[i]*prime[j];
				break;	
			}
			phi[i*prime[j]]=phi[i]*phi[prime[j]];
		}
	}
} 
int getsum(int n)
{
	if(n<=N)return pre[n];
	if(mp.count(n))return mp[n];
	int res=n*(n+1)%mod*(2*n+1)%mod*_6%mod;
	for(int l=2,r;l<=n;l=r+1)
	{
		r=n/(n/l);
		res-=(l+r)*(r-l+1)/2%mod*getsum(n/l)%mod; 
	}
	return mp[n]=res%mod;
}
int qpow(int a,int b,int mod)
{
	if(b==0)return 1;
	if(b%2==0)
	{
		int temp=qpow(a,b/2,mod)%mod;
		return temp*temp%mod;
	}
	else
	{
		return qpow(a,b-1,mod)*a%mod;
	}
}
main(void)
{
	init();
	for(int i=1;i<=N;i++)
	{
		pre[i]=(pre[i-1]+i*phi[i])%mod;
	}
	int t=read();
	_2=qpow(2,mod-2,mod);//2乘法逆元
	_6=qpow(6,mod-2,mod);//6乘法逆元 
	while(t--)
	{
		int n=read();
		int a=read();
		int b=read();
		printf("%lld\n",(getsum(n)-1+mod)%mod*_2%mod);
	}
	
}