51nod1584 加权约数和

我们把答案写成 2ni=1ij=1iσ(ij)ni=1σ(i2) ,对两部分分别求和。
后一部分比较简单, σ(i2) 是积性函数,且 σ((pxqp)2)=(σ((px)2)+p2x+1+p2x+2)σ(q2) ,可以线性筛。
考虑前一部分,首先我们知道, σ(mn)=i|nj|mije(gcd(ni,j)) 。那么

====i=1nij=1iσ(ij)i=1nij=1ia|iab|jjbk|gcd(a,b)μ(k)k=1nμ(k)i=1nkika|iakj=1ib|jjbk=1nμ(k)k2i=1nkg(i)K=1nk|Kμ(k)k2g(Kk)

在求出 g 函数之后,我们就可以O(nlogn)计算出 1 n的答案。而 g(n)=nσ(n)ni=1σ(i) 。线性筛求出 σ 的前缀和就可以了。
最后的复杂度是 O(nlogn+q)

#include<cstdio>
#include<algorithm>
using namespace std;
#define LL long long
const int p=1000000007,maxn=1000000;
int inv[maxn+10],prm[maxn+10],mu[maxn+10],mnp[maxn+10],mnpw[maxn+10],
f[maxn+10],g[maxn+10],h[maxn+10],
ssigma2[maxn+10],sigma[maxn+10],
n,tot;
int inc(int x,int y)
{
    x+=y;
    return x>=p?x-p:x;
}
int dec(int x,int y)
{
    x-=y;
    return x<0?x+p:x;
}
int pow(int b,int k)
{
    int ret=1;
    for (;k;k>>=1,b=(LL)b*b%p)
        if (k&1) ret=(LL)ret*b%p;
    return ret;
}
void init()
{
    int x;
    inv[1]=mu[1]=sigma[1]=ssigma2[1]=1;
    for (int i=2;i<=maxn;i++)
    {
        if (!mnp[i])
        {
            prm[++tot]=i;
            mnp[i]=mnpw[i]=i;
            mu[i]=p-1;
            inv[i]=pow(i,p-2);
            sigma[i]=i+1;
            ssigma2[i]=inc(inc((LL)i*i%p,i),1);
        }
        for (int j=1;j<=tot&&(LL)i*prm[j]<=maxn;j++)
        {
            x=i*prm[j];
            inv[x]=(LL)inv[i]*inv[prm[j]]%p;
            if (i%prm[j])
            {
                mnp[x]=mnpw[x]=prm[j];
                mu[x]=dec(0,mu[i]);
                sigma[x]=(LL)sigma[i]*sigma[prm[j]]%p;
                ssigma2[x]=(LL)ssigma2[i]*ssigma2[prm[j]]%p;
            }
            else
            {
                mnp[x]=prm[j];
                mnpw[x]=mnpw[i]*prm[j];
                mu[x]=0;
                sigma[x]=inc(sigma[i],(LL)prm[j]*mnpw[i]%p*sigma[i/mnpw[i]]%p);
                ssigma2[x]=inc(ssigma2[i],(LL)inc((LL)mnpw[i]*mnpw[i]%p*mnp[i]%p,(LL)mnpw[i]*mnpw[i]%p*mnp[i]%p*mnp[i]%p)*ssigma2[i/mnpw[i]]%p);
                break;
            }
        }
    }
    for (int i=1;i<=maxn;i++)
    {
        ssigma2[i]=inc(ssigma2[i-1],(LL)i*ssigma2[i]%p);
        h[i]=inc(h[i-1],sigma[i]);
        g[i]=(LL)i*h[i]%p*sigma[i]%p;
        for (int j=i;j<=maxn;j+=i) f[j]=inc(f[j],(LL)g[i]*mu[j/i]%p*(j/i)%p*(j/i)%p);
        f[i]=inc(f[i-1],f[i]);
    }
}
int main()
{
    init();
    int T;
    scanf("%d",&T);
    for (int K=1;K<=T;K++)
    {
        scanf("%d",&n);
        printf("Case #%d: %d\n",K,dec(inc(f[n],f[n]),ssigma2[n]));
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值