1. 程式人生 > 實用技巧 >【題解】「MCOI-02」Convex Hull 凸包

【題解】「MCOI-02」Convex Hull 凸包

題目戳我

\(\text{Solution:}\)

\[\sum_{i=1}^n \sum_{j=1}^n \rho(i)\rho(j)\rho(\gcd(i,j)) \]

\[=\sum_{d=1}^n \rho(d)\sum_{i=1}^n \sum_{j=1}^n \rho(i)\rho(j)\rho(\gcd(i,j))[\gcd(i,j)=d] \]

\[=\sum_{d=1}^n \rho(d)\sum_{i=1}^\frac{n}{d}\sum_{j=1}^\frac{n}{d}\rho(i*d)\rho(j*d)[\gcd(i,j)=1] \]

\[=\sum_{d=1}^n\rho(d) \sum_{k=1}^\frac{n}{d}\mu(k)\sum_{i=1}^\frac{n}{kd}\sum_{j=1}^\frac{n}{kd}\rho(i*kd)\rho(j*kd) \]

\[=\sum_{T=1}^n\sum_{d|T} \rho(d)\mu(\frac{T}{d})\sum_{i=1}^\frac{n}{T}\sum_{j=1}^\frac{n}{T}\rho(i*T)\rho(j*T) \]

\[=\sum_{T=1}^n \sum_{i=1}^\frac{n}{T}\sum_{j=1}^\frac{n}{T}\rho(i*T)\rho(j*T) \]

\(\rho*\mu=1*1*\mu=1*e\)即值始終為\(1.\)

這題所學到的主要是線性篩約數個數\(\rho\)

前提:唯一分解定理 \(n=\prod_{i=1}^k p_i^{a_i},\rho(n)=\prod (a_i+1)\)

\(g\)是最小質因數的次數,\(t\)是約數個數。

對於質數:顯然\(g=1,t=2(1,p).\)

\(n=i*p[j]:\)

\(i\equiv 0\bmod p[j],g[n]=g[i]+1,t[n]=\frac{t[i]*(g[n]+1)}{g(n)}\)

否則\(g[n]=1,t[n]=t[i]*2.\)

解釋:對於非質數的第二種情況,最小質因子次數一定是一個質數不必解釋,而因子個數由於多了一個質因子,所以由上述唯一分解定理會使得原來的\(g\)變為兩倍(多乘了一個\(c_p+1,c_p=1.\)

對於非質數的第一種情況,最小質因子一定是當前的\(p[j],\)所以最小質因子次數就是\(g[i]+1,\)

而約數個數需要先把\(i\)\(p[j]\)因子除盡再乘上當前的這個,實際上就是把\(c_{p[j]}\)加了一。

於是這題可以在不用 Dirichlet字首和 的情況下做到\(O(n\ln n+n\ln n).\)

#include<bits/stdc++.h>
using namespace std;
const int MAXN=2e6;
int n,m,pp,vis[MAXN+1],cnt,p[MAXN+1],t[MAXN+1],g[MAXN+1],Tn[MAXN+1],Tm[MAXN+1],ans;
inline int add(int x,int y){return (x+y)%pp;}
inline int mul(int x,int y){return 1ll*x*y%pp;}
inline void predo(){
	t[1]=1;
	for(int i=2;i<=MAXN;++i){
		if(!vis[i])p[++cnt]=i,g[i]=1,t[i]=2;
		for(int j=1;j<=cnt&&i*p[j]<=MAXN;++j){
			vis[i*p[j]]=1;
			if(i%p[j]==0){
				g[i*p[j]]=g[i]+1;
				t[i*p[j]]=mul(t[i]/g[i*p[j]],(g[i*p[j]]+1));
				break;
			}
			g[i*p[j]]=1;
			t[i*p[j]]=t[i]<<1;
		}
	}
}
int main(){
	scanf("%d%d%d",&n,&m,&pp);
	predo();
	if(n>m)swap(n,m);
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n/i;++j)
			Tn[i]=add(Tn[i],t[i*j]);
	for(int i=1;i<=m;++i)
		for(int j=1;j<=m/i;++j)
			Tm[i]=add(Tm[i],t[i*j]);
	for(int T=1;T<=n;++T)
		ans=add(ans,mul(Tn[T],Tm[T]));
	printf("%d\n",ans);
	return 0;
}