[SPOJ]DIVCNTK - Counting Divisors[數論]

VictoryCzt發表於2019-01-19

題目地址

  • 題目大意:

給定n,kn,k,求下面式子的值(對2642^{64}取模)

i=1nσ0(ik) \sum_{i=1}^n\sigma_{0}(i^k)

其中σ0\sigma_{0}是約數個數函式。

n,k1010n,k\leq 10^{10}


這個似乎可以用杜教篩之類的,但是比較麻煩,複雜度比較高,但如果用min_25min\_25就比較容易了。

我們只用考慮對於質數時的取值:

σ0(pk)=k+1 \sigma_0(p^k)=k+1

然後直接套min_25的式子就好啦!

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll unsigned long long
using namespace std;
const int M=2e6+10;
ll cnt,ID,n,sq,K;
ll idx(ll a){return a<=sq?a:ID-(n/a)+1;}
ll A[M],prime[M],g[M];
ll S(ll a,ll b){
	if(a<prime[b]) return 0;
	ll ans=g[idx(a)]-(K+1ll)*(b-1ll);
	for(ll i=b;i<=cnt&&prime[i]*prime[i]<=a;i++){
		for(ll j=prime[i],k=K+1ll;j*prime[i]<=a;j*=prime[i],k+=K){
			ans+=S(a/j,i+1)*k+(k+K);
		}
	}
	return ans;
}
int T;
int main(){
	for(scanf("%d",&T);T--;){
		scanf("%llu%llu",&n,&K);
		if(n==1){puts("1");continue;}
		sq=(ll)sqrt(n);ID=cnt=0;
		for(ll i=1;i<=n;i=A[ID]+1){
			A[++ID]=n/(n/i);
			g[ID]=(K+1ll)*(A[ID]-1ll);
		}
		for(ll i=2;i<=sq;i++)if(g[i]!=g[i-1]){
			prime[++cnt]=i;
			for(ll j=ID,down=i*i;A[j]>=down;j--){
				g[j]-=g[idx(A[j]/i)]-(K+1ll)*(cnt-1ll);
			}
		}
		printf("%llu\n",S(n,1)+1ll);
	}
	return 0;
}

相關文章