51nod1238 最小公倍數之和V3【杜教篩】

題意:

i=1nj=1nlcm(i,j)        mod 109​+​7n<=1010\sum_{i=1}^n\sum_{j=1}^nlcm(i,j) ~~~~~~~~mod~10^9\!+\!7\\n<=10^{10}

題目分析:

化簡,i=1nj=1nlcm(i,j)=i=1nj=1nijgcd(i,j)\sum_{i=1}^n\sum_{j=1}^nlcm(i,j)\\=\sum_{i=1}^n\sum_{j=1}^n\frac {i*j}{gcd(i,j)}
枚舉gcd=d=1ndi=1ndj=1nd[gcd(i,j)==1]ij=\sum_{d=1}^nd*\sum_{i=1}^{\frac nd}\sum_{j=1}^{\frac nd}[gcd(i,j)==1]*i*j
OK,且慢,這裏的gcd(i,j)==1就很講究了,有兩種方法

法一:歐拉函數 φ\varphi

因爲i=1ndj=1nd\sum_{i=1}^{\frac nd}\sum_{j=1}^{\frac nd}是對稱的,所以可以化爲
=d=1nd{(2i=1ndij=1ij[(i,j)==1])1}=d=1nd{(2i=1ndiiφ(i)+[i=1]2)1}=d=1ndi=1ndi2φ(i)=\sum_{d=1}^nd*\left\{\left(2\sum_{i=1}^{\frac nd}i\sum_{j=1}^ij[(i,j)==1]\right)-1\right\}\\=\sum_{d=1}^nd*\left\{\left(2\sum_{i=1}^{\frac nd}i*\frac{i*\varphi(i)+[i=1]}2\right)-1\right\}\\=\sum_{d=1}^nd*\sum_{i=1}^{\frac nd}i^2*\varphi(i)
然後按照d分塊優化,要求i2φ(i)i^2*\varphi(i)的前綴和,把它看做ididφid\cdot id\cdot\varphi
那麼(ididφ)(idid)=(id\cdot id\cdot\varphi)*(id\cdot id)=
ini2φ(i)(ni)2=n2inφ(i)=n3=id3\sum_{i|n}i^2*\varphi(i)*(\frac ni)^2\\=n^2\sum_{i|n}\varphi(i)\\=n^3\\=id^3
id2id3id^2和id^3的前綴和都很好求,所以問題就解決了
i=1ni3=i=1ndid2φ(d)(id)2=i=1ni2d=1nid2φ(d)=i=1ni2F(ni)\sum_{i=1}^ni^3=\sum_{i=1}^n\sum_{d|i}d^2*\varphi(d)*(\frac id)^2\\=\sum_{i=1}^ni^2\sum_{d=1}^{\frac ni}d^2*\varphi(d)\\=\sum_{i=1}^ni^2*F(\frac ni)
把i=1提出來,那麼F(n)=i=1ni3i=2ni2F(ni)F(n)=\sum_{i=1}^ni^3-\sum_{i=2}^ni^2*F(\frac ni)
i2φ(i)i^2*\varphi(i)是積性函數,可以線性篩一部分,然後分塊優化遞歸求解即可

法一的核心點:i=1ni[(n,i)==1]=nφ(n)+[n=1]2\sum_{i=1}^ni*[(n,i)==1]={n*\varphi(n)+[n=1]\over2}

因爲倘若i與n互質,則n-i也與n互質,這樣的對數有φ(n)/2\varphi(n)/2對,每對的和都爲n

法二:莫比烏斯反演 μ\mu

d=1ndi=1ndj=1nd[gcd(i,j)==1]ij=d=1ndi=1ndj=1ndijk(i,j)μ(k)=d=1ndk=1ndμ(k)k2i=1ndkj=1ndkij\sum_{d=1}^nd*\sum_{i=1}^{\frac nd}\sum_{j=1}^{\frac nd}[gcd(i,j)==1]*i*j\\=\sum_{d=1}^nd*\sum_{i=1}^{\frac nd}\sum_{j=1}^{\frac nd}i*j*\sum_{k|(i,j)}\mu(k)\\=\sum_{d=1}^nd*\sum_{k=1}^{\frac nd}\mu(k)k^2\sum_{i=1}^{\frac n{dk}}\sum_{j=1}^{\frac n{dk}}i*j
令dk=T
=T=1n(nT(nT+1)2)2kTμ(k)k2Tk\large=\sum_{T=1}^n({\frac nT*(\frac nT+1)\over2})^2*\sum_{k|T}\mu(k)*k^2*{\frac Tk}
按照T分塊優化,要求kTμ(k)k2Tk\sum_{k|T}\mu(k)*k^2*{\frac Tk}的前綴和(這時候最好不要把T提出去),把它看做(ididμ)id(id\cdot id\cdot\mu)*id
那麼(ididμ)id(idid)=(id\cdot id\cdot\mu)*id*(id\cdot id)=
(ididμ)(idid)id=(dTd2μ(d)(Td)2)id=(T2dTμ(d))id=TNT2(NT)dTμ(d)=NTNT[T==1]=id(id\cdot id\cdot\mu)*(id\cdot id)*id\\=\left(\sum_{d|T}d^2*\mu(d)*(\frac Td)^2\right)*id\\=\left(T^2\sum_{d|T}\mu(d)\right)*id\\=\sum_{T|N}T^2*(\frac NT)\sum_{d|T}\mu(d)\\=N\sum_{T|N}T[T==1]\\=id
id2idid^2和id的前綴和都很好求,剩下的部分就和法一的轉化方法類似了

法二的核心:[n==1]=dnμ(d)[n==1]=\sum_{d|n}\mu(d)
兩種方法的共同點:

都利用了卷積(遞歸方法)來求解n比較大時,通常n<=1e9,1e10,1e11,的前綴和問題,構造出fg=hf*g=h的形式,當g,h的前綴和可以O(1)求解,且f爲積性函數,可以線性篩一部分時,求解f的前綴和的時間複雜度爲O(n23)O(n^{\frac 23})

Ps:兩種方法都試圖通過卷積消去φ\varphiμ\mu前面的係數,從而簡化形式,這是個初學時很難想到的點(至少我沒想到。。。)。

此處貼出法一的代碼,法二請讀者自行嘗試。。。

#include<cstdio>
#include<map>
#define LL long long
using namespace std;
const int mod = 1e9+7, N = 5000000, inv2 = 5e8+4, inv6 = 166666668;
int p[N/10],sum[N+5];
bool v[N+5];
map<LL,int>F;
inline int sqr(int x){return 1ll*x*x%mod;}
void Prime()
{
	sum[1]=1;int cnt=0;
	for(int i=2;i<=N;i++)
	{
		if(!v[i]) p[++cnt]=i,sum[i]=1ll*i*i%mod*(i-1)%mod;
		for(int j=1,k;j<=cnt&&p[j]*i<=N;j++)
		{
			v[k=p[j]*i]=1;
			if(i%p[j]==0) {sum[k]=1ll*sum[i]*p[j]%mod*sqr(p[j])%mod;break;}
			sum[k]=1ll*sum[i]*sum[p[j]]%mod;
		}
	}
	for(int i=2;i<=N;i++) sum[i]=(sum[i]+sum[i-1])%mod;
}
inline LL calc(LL n){return n*(n+1)%mod*(2*n+1)%mod*inv6%mod;}
int solve(LL n)
{
	if(n<=N) return sum[n];
	if(F.count(n)) return F[n];
	int ret=sqr(n%mod*((n+1)%mod)%mod*inv2%mod);
	for(LL i=2,j;i<=n;i=j+1)
	{
		j=n/(n/i);
		ret=(ret-(calc(j%mod)-calc((i-1)%mod))*solve(n/i))%mod;
	}
	return F[n]=ret;
}
int main()
{
	Prime();
	LL n,ans=0;
	scanf("%lld",&n);
	for(LL i=1,j;i<=n;i=j+1)
	{
		j=n/(n/i);
		ans=(ans+(i+j)%mod*(j-i+1)%mod*inv2%mod*solve(n/i))%mod;
	}
	printf("%lld",(ans+mod)%mod);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章