1. 程式人生 > >BZOJ_4176_Lucas的數論_杜教篩+莫比烏斯反演

BZOJ_4176_Lucas的數論_杜教篩+莫比烏斯反演

sam -c return des AD ++ a* 表達式 its

BZOJ_4176_Lucas的數論_杜教篩+莫比烏斯反演

Description

去年的Lucas非常喜歡數論題,但是一年以後的Lucas卻不那麽喜歡了。

在整理以前的試題時,發現了這樣一道題目“求Sigma(f(i)),其中1<=i<=N”,其中 表示i的約數個數。他現在長大了,題目也變難了。 求如下表達式的值: 技術分享圖片 其中 表示ij的約數個數。 他發現答案有點大,只需要輸出模1000000007的值。

Input

第一行一個整數n。

Output

一行一個整數ans,表示答案模1000000007的值。

Sample Input

2

Sample Output

8

HINT

對於100%的數據n <= 10^9。


$f(nm)=\sum\limits_{i|n}\sum\limits_{j|m}[gcd(i,j)=1]$

證明:首先$ij|nm$,但直接枚舉$ij$會有些重復。

設$gcd(i,j)=k,a=i/k,b=j/k$

發現一定能枚舉到$i‘=a*k,j‘=b,$和$i‘‘=a,j‘‘=b*k$,此時$gcd(i‘,j‘)=gcd(i‘‘,j‘‘)=1$。

考慮$a*b*k$這個約數其實是被枚舉了兩次,不妨用這兩次中的一個來‘代表’$a*b*k*k$。

因此我們枚舉$gcd(i,j)=1$的$i,j$即可,只是此時$ij$可能有相等的,他們代表的約數不同。


可以舉$n=2,m=6$的例子自己手算一下。

$\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}f(ij)
=
\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum
\limits_{x|i}\sum\limits_{y|j}[gcd(x,y)=1]$

$=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum
\limits_{x|i}\sum\limits_{y|j}\sum\limits_{d|gcd(x,y)}\mu(d)$

$=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum
\limits_{x|i}\sum\limits_{y|j}\sum\limits_{d|gcd(x,y)}\mu(d)$

$=\sum\limits_{d=1}^{n}\mu(d)\sum\limits_{i=1}^{n/d}\sum\limits_{j=1}^{n/d}\sum
\limits_{x=1}^{\frac{n/d}{i}}\sum\limits_{y=1}^{\frac{n/d}{j}}$

$=\sum\limits_{d=1}^{n}\mu(d)(\sum\limits_{i=1}^{n/d}\frac{n/d}{i})^{2}$

$\mu$的前綴和用杜教篩搞,後面的只有$\sqrt{n/d}$種取值。

代碼:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <map>
using namespace std;
typedef long long ll;
ll mod=1000000007;
map<ll,ll>f;
int m=1000000;
int prime[1000050],cnt,miu[1000050],summiu[1000050];
bool vis[1000050];
ll calc1(ll n) {
	if(n<=m) return summiu[n];
	if(f.count(n)) return f[n];
	ll i,lst,ans=1;
	for(i=2;i<=n;i=lst+1) {
		lst=n/(n/i);
		ans=(ans-(lst-i+1)*calc1(n/i)%mod+mod)%mod;
	}
	return f[n]=ans;
}
ll calc2(ll n)
{
    ll ans=0,i,lst;
    for(i=1;i<=n;i=lst+1) {
    	lst=n/(n/i);
    	ans=(ans+n/i*(lst-i+1))%mod;
    }
    return ans*ans%mod;
}
void init() {
	int i,j;
	miu[1]=summiu[1]=1;
	for(i=2;i<=m;i++) {
		if(!vis[i]) {
			prime[++cnt]=i;
			miu[i]=-1;
		}
		for(j=1;j<=cnt&&i*prime[j]<=m;j++) {
			vis[i*prime[j]]=1;
			if(i%prime[j]==0) {
				miu[i*prime[j]]=0;
				break;
			}
			miu[i*prime[j]]=-miu[i];
		}
		summiu[i]=summiu[i-1]+miu[i];
	}
}
int main() {
	init();
	ll n,ans=0,i,lst;
	scanf("%lld",&n);
	for(i=1;i<=n;i=lst+1) {
		lst=n/(n/i);
		ans=(ans+(calc1(lst)-calc1(i-1)+mod)%mod*calc2(n/i))%mod;
	}
	printf("%lld\n",ans);
}

BZOJ_4176_Lucas的數論_杜教篩+莫比烏斯反演