我是靠谱客的博主 温暖豆芽,最近开发中收集的这篇文章主要介绍[SPOJ] DIVCNT2 - Counting Divisors (square) 积性函数前缀和,觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
题面
题目要我们求
∑i=1nσ0(i2)
把 i 分解质因数
就是求
∑i=1n∏j=1k(2αj+1)
考虑每个乘式选 2αj 还是 1 ,枚举集合就是
把 S 集合看成选
其实把 ω(d) 看成每个质因数选或不选,就是 d 的无平方因子约数的个数,所以式子变成
改成枚举 μ2(i) ,就是
∑i=1nμ2(i)∑j=1⌊ni⌋σ0(j)
于是利用整除分块,我们只要知道 μ2(i) 和 σ0(i) 的前缀和,按照杜教筛的复杂度分析,就能在预处理前 n23 项的情况下, O(n23) 求出。
前者就是 1 n 的无平方因子数个数,考虑容斥 O(n√)
∑i=1nμ2(i)=∑i=1n√μ(i)∗⌊ni2⌋
后者就是sb套路,整除分块 O(n√)
∑i=1nσ0(i)=∑i=1n⌊ni⌋
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define ll long long
using namespace std;
const int maxn=50000000;
ll n;
int pri[10000000],num,mu[maxn+5],d[maxn+5],sm[maxn+5],sd[maxn+5],ci[maxn+5];
bool flag[maxn+5];
void getpri(int n)
{
memset(flag,1,sizeof(flag));
flag[1]=0;mu[1]=1;d[1]=1;
for(int i=2;i<=n;i++)
{
if(flag[i]) pri[++num]=i,mu[i]=-1,ci[i]=1,d[i]=2;
for(int j=1;j<=num&&i*pri[j]<=n;j++)
{
int v=i*pri[j];
flag[v]=0;ci[v]=1;
if(i%pri[j]==0) {ci[v]+=ci[i];mu[v]=0;d[v]=d[i]*(ci[v]+1)/ci[v];break;}
mu[v]=-mu[i];d[v]=(d[i]<<1);
}
}
}
ll qsd(ll m)
{
if(m<=maxn) return sd[m];
ll re=0;
for(ll l=1,r=1,k;l<=m;l=r+1)
{
k=m/l;r=m/k;
re+=(ll)(r-l+1)*k;
}
return re;
}
ll qsm(ll m)
{
if(m<=maxn) return sm[m];
ll gen=round(sqrt(m)+1),re=0;
for(ll i=1;i<=gen;i++)
re+=mu[i]*(m/(i*i));
return re;
}
ll solve()
{
ll re=0;
for(ll l=1,r=1,k;l<=n;l=r+1)
{
k=n/l;r=n/k;
re+=qsd(k)*(qsm(r)-qsm(l-1));
}
return re;
}
int main()
{
int ca,lim=maxn;
scanf("%d",&ca);
if(ca>800) lim=10000;
getpri(lim);
for(int i=1;i<=lim;i++)
sm[i]=sm[i-1]+mu[i]*mu[i],sd[i]=sd[i-1]+d[i];
while(ca--)
{
scanf("%lld",&n);
printf("%lldn",solve());
}
return 0;
}
最后
以上就是温暖豆芽为你收集整理的[SPOJ] DIVCNT2 - Counting Divisors (square) 积性函数前缀和的全部内容,希望文章能够帮你解决[SPOJ] DIVCNT2 - Counting Divisors (square) 积性函数前缀和所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复