【SPOJ-DIVCNTK】Counting Divisors (general)(min_25筛)

传送门


题解:

f ( i ) = σ 0 ( i k ) f(i)=\sigma_0(i^k) f(i)=σ0(ik),显然由于 σ 0 ( i ) \sigma_0(i) σ0(i)是一个积性函数,则 σ 0 ( i k ) \sigma_0(i^k) σ0(ik)是一个积性函数。

以下介绍的是min_25求积性函数前缀和的第二部分,第一部分请参考LOJ6235

显然这道题的质数点值前缀和直接算质数个数后乘上 k + 1 k+1 k+1就行了。

考虑把所有点值的前缀和算出来。

S ( n , i ) = ∑ j = 2 n [ m i n p r ( j ) ≥ p i ] f ( j ) S(n,i)=\sum\limits_{j=2}^n[minpr(j)\geq p_i]f(j) S(n,i)=j=2n[minpr(j)pi]f(j)

则我们要求的就是 S ( n , 1 ) + f ( 1 ) S(n,1)+f(1) S(n,1)+f(1),补上 1 1 1处的点值。

质数的答案显然已经有了,就是 g ( n , ∣ P ∣ ) − ∑ j = 1 i − 1 f ( p j ) g(n,|P|)-\sum_{j=1}^{i-1}f(p_j) g(n,P)j=1i1f(pj)

那么根据函数的积性,我们枚举最小质因子和最小质因子的次数转移就行了。

方程为 S ( n , i ) = g ( n , ∣ P ∣ ) − ∑ j = 1 i − 1 f ( p j ) + ∑ j = i p j 2 ≤ n ∑ t = 1 p j t + 1 ≤ n S ( ⌊ n p j t ⌋ , j + 1 ) ⋅ f ( p j t ) + f ( p j t + 1 ) S(n,i)=g(n,|P|)-\sum_{j=1}^{i-1}f(p_j)+\sum_{j=i}^{p_j^2\leq n}\sum_{t=1}^{p_j^{t+1}\leq n}S(\lfloor\frac{n}{p_j^t}\rfloor,j+1)\cdot f(p_j^t)+f(p_j^{t+1}) S(n,i)=g(n,P)j=1i1f(pj)+j=ipj2nt=1pjt+1nS(pjtn,j+1)f(pjt)+f(pjt+1)

不需要记忆化,时间复杂度不受影响。

记忆化的优化效果也微乎其微,因为子问题重叠率不高。


代码:

#include<bits/stdc++.h>
#define ll unsigned long long
#define re register
#define cs const

cs int N=1e6+7;

int lim,tot,p[N];
ll f1[N],f2[N];
ll n,k;

inline void init(){
	lim=sqrt(n);tot=0;
	for(int re i=1;i<=lim;++i)f1[i]=i-1,f2[i]=n/i-1;
	for(int re p=2;p<=lim;++p)if(f1[p]!=f1[p-1]){
		::p[++tot]=p;ll t=f1[p-1];
		for(int re i=1,li=lim/p;i<=li;++i)f2[i]-=f2[i*p]-t;
		for(int re i=lim/p+1,li=std::min(n/p/p,(ll)lim);i<=li;++i)f2[i]-=f1[n/i/p]-t;
		if((ll)p*p<=lim)for(int re i=lim,li=p*p;i>=li;--i)f1[i]-=f1[i/p]-t;
	}
}

ll solve(ll n,int i){
	ll g=(n<=lim)?f1[n]:f2[::n/n];
	ll ans=(k+1)*(g-f1[p[i-1]]);
	for(int re j=i;j<=tot;++j){
		if((ll)p[j]*p[j]>n)break;
		for(ll now=p[j],t=1;now<=n;now*=p[j],++t){
			if(now*p[j]<=n)ans+=(k*t+1)*solve(n/now,j+1);
			if(t>1)ans+=(k*t+1);
		}
	}
	return ans;
}

signed main(){
	int T;std::cin>>T;
	while(T--){
		std::cin>>n>>k;init();
		std::cout<<solve(n,1)+1<<"\n";
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值