[2017集训队作业自选题#148]Simple Summation Problem

题目大意

定义一个积性函数F。
若p为质数, F(pd)=pd[d mod p!=0]
求F的前缀和。

做法

G=Fμ ,那么G也是一个积性函数。
那么容易得到 G(pd)=pd[d mod p!=0]pd1[(d1) mod p!=0]
d=1时G(p)=0。
所以G不为0,则必须每个质因子指数均>=2。
然后莫比乌斯反演得到 F(n)=d|nG(d)
ni=1F(i)=ni=1d|iG(d)
即答案为 nd=1G(d)ni
枚举出所有质因子指数均>=2的d计算即可。

#include<cstdio> 
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn=10000000+10;
int pri[maxn],id[maxn],f[maxn],g[maxn],h[maxn],L[maxn],sta[100][2];
//ll mi[maxn*3],G[maxn*3];
bool bz[maxn];
int i,j,k,l,m,tot,top,cnt;
ll n,N,t,ans;
void prepare(){
    N=floor(sqrt(n));
    fo(i,2,N){
        if (!bz[i]){
            pri[++top]=i;
            id[i]=top;
            f[i]=h[i]=i;
            g[i]=1;
        }
        fo(j,1,top){
            if ((ll)i*pri[j]>N) break;
            bz[i*pri[j]]=1;
            f[i*pri[j]]=pri[j];
            if (i%pri[j]==0){
                g[i*pri[j]]=g[i]+1;
                h[i*pri[j]]=h[i]*pri[j];
                break;
            }
            g[i*pri[j]]=1;
            h[i*pri[j]]=pri[j];
        }
    }
    /*fo(i,1,top){
        L[i]=++tot;
        mi[tot]=t=1;
        G[tot]=0;
        j=0;
        while (t<=(ll)n/pri[i]){
            j++;
            t*=pri[i];
            mi[++tot]=t;
            G[tot]=mi[tot-(j%pri[i]!=0)]-mi[tot-1-((j-1)%pri[i]!=0)];
        }
    }*/
}
/*ll G(int p,int c){
    ll t=mi[L[p]+c-(c%pri[p]!=0)];
    t-=mi[L[p]+c-1-((c-1)%pri[p]!=0)];
    return t;
}*/
void dfs(ll x,ll y,ll z){
    if (!z) return;
    ll p=pri[x];
    if (x==top+1||y>n/p/p){
        ans+=n/y*z;
        return;
    }
    dfs(x+1,y,z);
    ll i=2,j,m=n/y;
    ll t=p,l=1,r;
    m/=t;
    while (m>=p){
        t*=p;
        r=l;
        if ((i-1)%p!=0) r*=p;
        if (i%p==0) r*=p;
        dfs(x+1,y*t,z*(r-l));
        l=r;
        i++;
        m/=p;
    }
}
/*void dg(int x,ll y,ll z,ll m){
    if (!z) return;
    ll t;
    int p=sta[x][0],c=sta[x][1];
    if (x==cnt+1){
        ans+=n/y*z;
        return;
    }
    t=mi[L[p]+2*c];
    dg(x+1,y*t,z*G[L[p]+2*c],m);
    if (m>=pri[p]){
        t*=pri[p];
        dg(x+1,y*t,z*G[L[p]+2*c+1],m/pri[p]);
    }
}
void work(int x){
    cnt=0;
    while (x>1){
        cnt++;
        sta[cnt][0]=id[f[x]];
        sta[cnt][1]=g[x];
        x/=h[x];
    }
    dg(1,1,1,(ll)n/x/x);
}*/
int main(){
    scanf("%lld",&n);
    prepare();
    dfs(1,1,1);
    //fo(i,1,N) work(i);
    printf("%lld\n",ans);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值