【題解】SP34096 DIVCNTK - Counting Divisors (general)
阿新 • • 發佈:2021-07-31
題目大意:求 \(\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; }