您的位置:首页 > 其它

[莫比乌斯反演] CCPC 2016 Hangzhou J & HDU 5942 Just a Math Problem

2017-03-30 07:59 447 查看
记f(k)表示k的素因子个数,g(k)=2f(k)。

求g(1)+…+g(n)。

n≤1012

g(k)的组合意义为满足(i,j)=1且ij=k的对数。

所以变成求(i,j)=1且ij≤n的对数。

∑ij≤n[(i,j)=1]===∑ij≤n∑d|i d|jμ(d)∑d=1n√μ(d)∑ij≤⌊nd2⌋1∑d=1n√μ(d)∑i=1⌊nd2⌋⌊nd2i⌋

复杂度O(n√lnn)

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;

const int maxn=1000000;
const int P=1e9+7;

int prime[maxn+5],vst[maxn+5],num;
int miu[maxn+5];

inline void Pre(int n){
miu[1]=1;
for (int i=2;i<=n;i++){
if (!vst[i]) prime[++num]=i,miu[i]=-1;
for (int j=1;j<=num && (ll)i*prime[j]<=n;j++){
vst[i*prime[j]]=1;
if (i%prime[j]==0){
miu[i*prime[j]]=0; break;
}
miu[i*prime[j]]=-miu[i];
}
}
}

inline ll calc(ll n){
ll ret=0; ll l,r;
for (l=1;l*l<=n;l++) ret+=n/l;
for (ll t=n/l;l<=n;l=r+1,t--)
r=n/t,ret+=(r-l+1)*t%P;
return ret%P;
}

inline ll Solve(ll n){
ll ret=0;
for (int i=1;(ll)i*i<=n;i++)
if (miu[i])
ret+=miu[i]==1?calc(n/i/i):P-calc(n/i/i);
return ret%P;
}

int main(){
int T,Case=0; ll n;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
scanf("%d",&T); Pre(maxn);
while (T--){
scanf("%I64d",&n);
printf("Case #%d: %I64d\n",++Case,Solve(n));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: