[SPOJ]DIVCNTK - Counting Divisors[数论]

题目地址

  • 题目大意:

给定 n , k n,k n,k,求下面式子的值(对 2 64 2^{64} 264取模)

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

其中 σ 0 \sigma_{0} σ0是约数个数函数。

n , k ≤ 1 0 10 n,k\leq 10^{10} n,k1010


这个似乎可以用杜教筛之类的,但是比较麻烦,复杂度比较高,但如果用 m i n _ 25 min\_25 min_25就比较容易了。

我们只用考虑对于质数时的取值:

σ 0 ( p k ) = k + 1 \sigma_0(p^k)=k+1 σ0(pk)=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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

VictoryCzt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值