[杜教筛+莫比乌斯反演] HDU5608: function

来源:互联网 发布:jsp项目绑定域名 编辑:程序博客网 时间:2024/06/02 10:42

题意这里写图片描述

题解

我们设 g(i)=i23i+2,题目告诉我们的就是 g=f1。然后就可以根据杜教筛的思路搞了:

i=1ng(i)=i=1nd|if(d)=i=1ndnif(d)=i=1nS(ni)

S(n)=i=1ng(i)i=2nS(ni)

如何不预处理前面一部分的话 O(n34) 可能会T掉,所以先要求一段,怎么求呢?
反演一下, g=f1f(n)=(gμ)(n)=d|ng(d)μ(nd),然后nlnn 暴力算就好了。

#include<cstdio> #include<cstring>#include<algorithm>#include<tr1/unordered_map>  using namespace std;  using namespace std::tr1;typedef long long LL;const int N=1000000, maxn=N+5;const LL MOD=1000000007, inv=(MOD+1)/3;  int Q,p[maxn],mu[maxn];bool vis[maxn];int sum[maxn];void Pre(){    memset(vis,1,sizeof(vis));    mu[1]=1;    for(int i=2;i<=N;i++){        if(vis[i]) p[++p[0]]=i, mu[i]=-1;        for(int j=1;j<=p[0]&&p[j]*i<=N;j++){            vis[p[j]*i]=false;            if(i%p[j]==0){ mu[p[j]*i]=0; break; }            mu[p[j]*i]=-mu[i];        }    }    for(int i=1;i<=N;i++)     for(int j=1;(LL)i*j<=N;j++) (sum[i*j]+=((LL)i-1)*(i-2)*mu[j]%MOD)%=MOD;    for(int i=1;i<=N;i++) (sum[i]+=sum[i-1])%=MOD;}unordered_map<int, int> lst;int Sum(int n){    if(n<=N) return (sum[n]+MOD)%MOD;     if(lst.find(n)!=lst.end()) return lst[n];    int res=((LL)n)*(n-1)%MOD*(n-2)%MOD*inv%MOD;    for(LL i=2,nxt;i<=n;i=nxt+1){        nxt=n/(n/i); (res+=MOD-(nxt-i+1)*Sum(n/i)%MOD)%=MOD;    }    return lst[n]=(res+MOD)%MOD;}int main(){    freopen("hdu5608.in","r",stdin);    freopen("hdu5608.out","w",stdout);    Pre();      scanf("%d",&Q);      while (Q--){          int n; scanf("%d",&n);          printf("%d\n",Sum(n));      }     return 0;}