人生有信仰 数据有梯度 暴力不爆零


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

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[N],pri[N],tot;
bool vs[N];
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;
}

 

posted @ 2017-11-22 17:43  lkhll  阅读(273)  评论(0编辑  收藏  举报