1. 程式人生 > >●BZOJ 4176 Lucas的數論

●BZOJ 4176 Lucas的數論

.cn ati urn rime 約數 .com 題目中的 col pre

題鏈:

http://www.lydsy.com/JudgeOnline/problem.php?id=4176

題解:

莫比烏斯反演,杜教篩

首先有這麽一個結論:

令d(n)表示n的約數的個數(就是題目中的f(n)),則有

$$d(nm)=\sum_{i|n}\sum_{j|m}[gcd(i,j)==1]$$

●BZOJ 3994 [SDOI2015]約數個數和也用到了這個東西。

那麽就下來接直接進行求ANS的式子的推導:

$$\begin{aligned}
ANS&=\sum_{n=1}^{N}\sum_{m=1}^{N}d(nm)\\
&=\sum_{n=1}^{N}\sum_{m=1}^{N}\sum_{i|n}\sum_{j|m}[gcd(i,j)==1]\\

&=\sum_{n=1}^{N}\sum_{m=1}^{N}\sum_{i|n}\sum_{j|m}\sum_{d|gcd(i,j)}\mu(d)\\
&=\sum_{d=1}^{N}\mu(d)\sum_{d|i}\sum_{d|j}\sum_{i|n,n\leq N}\sum_{j|m,m\leq N} 1\\
&=\sum_{d=1}^{N}\mu(d)(\sum_{d|i}\lfloor \frac{N}{i} \rfloor)^2\\
&=\sum_{d=1}^{N}\mu(d)(\sum_{i=1}^{\lfloor \frac{N}{d} \rfloor}\lfloor \frac{N}{id} \rfloor)^2\end{aligned}$$

令$$f(n)=\sum_{i=1}^{n}\lfloor \frac{n}{i} \rfloor$$

則$$ANS=\sum_{d=1}^{N}\mu(d)f(\lfloor \frac{N}{d} \rfloor)^2$$

這個求ANS的式子是可以分塊+杜教篩(求每塊$\mu$的和)做的,

同時求f也可以分塊求,

即這是一個塊套塊。。。

代碼:

#include<bits/stdc++.h>
#define DJM /*5623413*/ 1000000
using namespace std;
const int mod=1000000007;
struct Hash_Table{
	#define Hmod 1425367
	int org[DJM],val[DJM],nxt[DJM],head[Hmod],hnt;
	Hash_Table(){hnt=1;}
	void Push(int x,int v){
		static int u; u=x%Hmod;
		org[hnt]=x; val[hnt]=v; nxt[hnt]=head[u]; head[u]=hnt++;
	}
	int Find(int x){
		static int u; u=x%Hmod;
		for(int i=head[u];i;i=nxt[i])
			if(org[i]==x) return val[i];
		return -1;
	}
}H;
int pmu[DJM+50],mu[DJM+50];
void Sieve(){
	static bool np[DJM+50];
	static int prime[DJM+50],pnt;
	mu[1]=1;
	for(int i=2;i<=DJM;i++){
		if(!np[i]) prime[++pnt]=i,mu[i]=-1;
		for(int j=1;j<=pnt&&i<=DJM/prime[j];j++){
			np[i*prime[j]]=1;
			if(i%prime[j]) mu[i*prime[j]]=-mu[i];
			else break;
		}
	}
	for(int i=1;i<=DJM;i++)
		pmu[i]=(1ll*mod+pmu[i-1]+mu[i])%mod;
}
int f(int n){
	int ret=0;
	for(int i=1,last;i<=n;i=last+1){
		last=n/(n/i);
		ret=(1ll*ret+1ll*(last-i+1)*(n/i))%mod;
	}
	return ret;
}
int DJ_pmu(int n){
	if(n<=DJM) return pmu[n];
	if(H.Find(n)!=-1) return H.Find(n);
	int ret=1;
	for(int i=2,last;i<=n;i=last+1){
		last=n/(n/i);
		ret=(1ll*ret+mod-1ll*(last-i+1)*DJ_pmu(n/i)%mod)%mod;
	}
	H.Push(n,ret);
	return ret;
}
int main(){
	Sieve(); int n,ans=0;
	scanf("%d",&n);
	for(int d=1,tmp,last;d<=n;d=last+1){
		last=n/(n/d); tmp=f(n/d);
		tmp=1ll*tmp*tmp%mod;
		ans=(1ll*ans+(1ll*DJ_pmu(last)-DJ_pmu(d-1)+mod)%mod*tmp%mod)%mod;
	}
	printf("%d\n",ans);
	return 0;
}

  

●BZOJ 4176 Lucas的數論