您的位置:首页 > 其它

bzoj 4176: Lucas的数论 -- 杜教筛,莫比乌斯反演

2017-11-22 17:43 295 查看

4176: Lucas的数论

Time Limit: 30 Sec Memory Limit: 256 MB

Description

去年的Lucas非常喜欢数论题,但是一年以后的Lucas却不那么喜欢了。

在整理以前的试题时,发现了这样一道题目“求Sigma(f(i)),其中1<=i<=N”,其中 表示i的约数个数。他现在长大了,题目也变难了。
求如下表达式的值:



其中 表示ij的约数个数。
他发现答案有点大,只需要输出模1000000007的值。

Input

第一行一个整数n。

Output

一行一个整数ans,表示答案模1000000007的值。

Sample Input

2

Sample Output

8

HINT

对于100%的数据n <= 10^9。

Source

emmmm,转载一份题解吧,写的很清晰了 http://blog.csdn.net/clove_unique/article/details/67633389

我们先反演一下,化简成这样



然后就括号内的东西可以O(√n)算出,然后杜教筛出mu值,就可以了

(复杂度不要问我qwq

#include<map>
#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define mod 1000000007
#define ll long long
#define N 1000555
int mu
,pri
,tot;
bool vs
;
void INIT()
{
mu[1]=1;
for(int i=2;i<N;i++)
{
if(!vs[i]) pri[++tot]=i,mu[i]=-1;
for(int j=1;j<=tot&&pri[j]*i<N;j++)
{
vs[pri[j]*i]=1;
if(i%pri[j]==0){mu[pri[j]*i]=0;break;}
mu[pri[j]*i]=-mu[i];
}
mu[i]+=mu[i-1];
}
}
int n;
ll ans;
ll F(int x)
{
ll tp=0;
for(int i=1,j;i<=x;i=j+1)
{
j=x/(x/i);
(tp+=(ll)(x/i)*(j-i+1))%=mod;
}
return tp*tp%mod;
}
map<int,int>p;
ll sol(int x)
{
if(x<N) return mu[x];
if(p[x]) return p[x];
ll ta=1;
for(int i=2,j;i<=x;i=j+1)
{
j=x/(x/i);
(ta-=sol(x/i)*(j-i+1))%=mod;
}
if(ta<0) ta+=mod;
return p[x]=ta;
}
int main()
{
INIT();
scanf("%d",&n);
for(int i=1,j;i<=n;i=j+1)
{
j=n/(n/i);
(ans+=F(n/i)*(sol(j)-sol(i-1)+mod))%=mod;
}
printf("%lld\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: