1. 程式人生 > 其它 >【題解】SP34096 DIVCNTK - Counting Divisors (general)

【題解】SP34096 DIVCNTK - Counting Divisors (general)

題目大意:求 \(\sum_{i=1}^n \rho(i^k)\)

觀察一下它的性質:(下面簡記 \(p\) 為質數)

  • \(f(p)=\rho(p^k)=k+1\)

  • \(f(p^\alpha)=\rho(p^{\alpha k} )=\alpha k+1\)

  • \(f(ab)=\rho((ab)^k)=\rho(a^k)\rho(b^k)=f(a)f(b)[\gcd(a,b)=1]\)

於是它滿足:是積性函式,在 \(p,p^k\) 的值可以快速計算。

於是就可以用 Min_25 篩了,複雜度是 \(O(\frac{n^{\frac{3}{4}}}{\log n})\)

這篇題解沒有講關於 Min_25 的具體實現,主要是想要說一下做的時候遇到的問題:

求 Min_25 中 \(g\) 陣列的過程中是需要把 \(f(x)\) 拆解成一些完全積性函式的,這個時候我把 \(f(p)=k+1\) 拆成了 \(f_0(p)=1,f_1(p)=k\) 兩個函式,乍一看沒什麼問題,但仔細想想會發現:

\([\gcd(a,b)=1]f(ab)=f(a)f(b)=k^2\not =k\)

所以這個 \(f_1\) 並不是積性函式!

以後拆的時候一定要注意,不能看著像就寫上了,要不然調好久都不知道為啥。

程式碼:

#include<bits/stdc++.h>
using namespace std;
#define int unsigned long long
typedef unsigned long long ull;
const int N=2e5+10;
namespace Min_25{
	ull T,g1[N],w[N];
	ull sp,n,k,id1[N],id2[N];
	int sq,cnt,m,p[N],sum1[N];
	bool vis[N];
	void pre(){
		for(int i=2;i<=sq;++i){
			if(!vis[i])p[++cnt]=i;
			for(int j=1;j<=cnt&&i*p[j]<=sq;++j){
				vis[i*p[j]]=1;
				if(i%p[j]==0)break;
			}
		}
		for(int i=1;i<=cnt;++i)sum1[i]=sum1[i-1]+1;
	}
	inline ull f1(ull x){return x;}
	inline ull getid(ull x){if(x<=sq)return id1[x];return id2[n/x];}
	ull S(ull x,int j){
		if(p[j]>x)return 0;
		ull Ans=(g1[getid(x)])-(sum1[j]+sum1[j]*k);
		for(int i=j+1;i<=cnt&&p[i]*p[i]<=x;++i){
			for(int e=1,sp=p[i];sp<=x;sp*=p[i],++e){
				Ans+=(k*e+1)*(S(x/sp,i)+(e>1));
			}
		}
		return Ans;
	}
	inline void write(ull x){
		if(x>9)write(x/10);
		putchar(x%10+'0');
	}
	void solve(){
		cin>>T;
		sq=100000;
		pre();
		while(T--){
			cin>>n>>k;
			for(ull l=1,r;l<=n;l=r+1){
				ull d=n/l;
				w[++m]=d;r=n/d;
				g1[m]=f1(w[m])-1;
				if(w[m]<=sq)id1[w[m]]=m;
				else id2[r]=m;
			} 
			for(int i=1;i<=cnt;++i)
				for(int j=1;j<=m&&p[i]*p[i]<=w[j];++j){
					g1[j]=g1[j]-(g1[getid(w[j]/p[i])]-sum1[i-1]);
				}
			for(int j=1;j<=m;++j)g1[j]=g1[j]*(k+1);
			write(S(n,0)+1);putchar('\n');
			for(int i=1;i<=m;++i)id1[w[m]]=id2[w[m]]=0,g1[i]=w[i]=0;
			m=0;
		}
	}
}
signed main(){
	Min_25::solve();
	return 0;
}