51nod 1584 加权约数和

版权声明:原来这里可以拿来卖萌ヽ(・∀・)ノ https://blog.csdn.net/u012345506/article/details/86292618

本来想用:
i = 1 n j = 1 i i σ ( i j ) = i = 1 n i k = 1 i 2 k i k ( i , k ) \sum_{i=1}^n\sum_{j=1}^ii \sigma(ij)=\sum_{i=1}^ni\sum_{k=1}^{i^2}k\lfloor \frac i {\frac k {(i,k)}}\rfloor
来推的,结果没推出来,之后可能会再尝试推一下。

但是从上面这个式子的来历来分析,对于任意的数 k k i i 对其作为 i j ij 的因数的贡献只有 ( i , k ) (i,k) ,剩余的部分必须由 j j 承担,换言之,若一个数 k k i j ij 的因数,则必然满足 k ( i , k ) j \frac k {(i,k)}|j ,于是我们尝试枚举 i ( i , k ) \frac i {(i,k)} k ( i , k ) \frac k {(i,k)} ,当然,实际上他们分别是 i i j j 的因数,于是便有了一个更加方便的公式:
σ ( i j ) = a i b j [ ( a , b ) = 1 ] a j b \sigma(ij)=\sum_{a|i}\sum_{b|j}[(a,b)=1]a\frac j b

进入推导:
i = 1 n j = 1 i i σ ( i j ) = i = 1 n j = 1 i i a i b j [ ( a , b ) = 1 ] a b = x = 1 n μ ( x ) i = 1 n x j = 1 i x 2 i a i a σ ( j ) = x = 1 n x 2 μ ( x ) i = 1 n x i a i j = 1 i σ ( j ) = x = 1 n x 2 μ ( x ) i = 1 n x i σ s 2 ( i ) a i 1 = x = 1 n x 2 μ ( x ) i = 1 n x i σ s 2 ( i ) σ ( i ) \sum_{i=1}^n\sum_{j=1}^ii\sigma(ij)=\sum_{i=1}^n\sum_{j=1}^ii\sum_{a|i}\sum_{b|j}[(a,b)=1]ab\\ =\sum_{x=1}^n\mu(x)\sum_{i=1}^{\lfloor \frac n x\rfloor}\sum_{j=1}^ix^2i\sum_{a|i}a\sigma(j)\\ =\sum_{x=1}^nx^2\mu(x)\sum_{i=1}^{\lfloor \frac n x\rfloor}i\sum_{a|i}\sum_{j=1}^i\sigma(j)\\ =\sum_{x=1}^nx^2\mu(x)\sum_{i=1}^{\lfloor \frac n x\rfloor}i\sigma_s^2(i)\sum_{a|i}1\\ =\sum_{x=1}^nx^2\mu(x)\sum_{i=1}^{\lfloor \frac n x \rfloor}i\sigma _s^2(i)\sigma(i)

容易想到通过递推来预处理所有的值,因为当 n + 1 i \lfloor \frac {n+1} i\rfloor 变化时,当且仅当 i n + 1 i|n+1 ,设:
f ( n ) = i = 1 n j = 1 i i σ ( i j ) = f ( n 1 ) + d n d 2 μ ( d ) ( i d ) σ s 2 ( i d ) σ ( i d ) f(n)=\sum_{i=1}^n\sum_{j=1}^ii\sigma(ij)\\ =f(n-1)+\sum_{d|n}d^2\mu(d)(\frac i d)\sigma_s^2(\frac i d)\sigma(\frac i d)
这使得我们可以在 O ( n l g o n ) O(nlgon) 下预处理出所有答案。

当然,为了求出正确解,还需要计算 i = 1 n i σ ( i 2 ) \sum_{i=1}^ni\sigma(i^2) 的值,因为很简单所以就不写了。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<climits>
#include<cstdio>
#include<cmath>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
//--Container
//--
typedef long long ll;
const ll md=1e9+7;const int up=1e6;
int ct=0,mu[up+10],pr[up+10],pn,ms[up+10];ll mss[up+10],rs[up+10];bool bd[up+10];

void _init(){
    int i,j,k,d,t;for(pn=0,i=2;i<=up;++i){
        if(!bd[i])pr[++pn]=i,mu[i]=-1;
        for(j=1;j<=pn&&(ll)pr[j]*i<=up;++j){
            bd[pr[j]*i]=1,mu[pr[j]*i]=-mu[i];
            if(!(i%pr[j])){mu[pr[j]*i]=0;break;}
        }
    }
    for(i=1;i<=up;++i)for(j=i;j<=up;j+=i)ms[j]+=i;
    for(mu[1]=1,i=2;i<=up;++i)mu[i]=mu[i]<0?mu[i]+md:mu[i];
    for(i=1;i<=up;++i)mss[i]=(mss[i-1]+ms[i])%md;
    for(i=1;i<=up;++i)for(j=i;j<=up;j+=i){
        t=j/i;rs[j]=(rs[j]+(ll)i*i%md*mu[i]%md*t%md*ms[t]%md*mss[t]%md*2)%md;
        rs[j]=(rs[j]+md-(ll)i*i%md*mu[i]%md*(t)%md*ms[t]%md*ms[t]%md)%md;
    }
    for(i=2;i<=up;++i)rs[i]=(rs[i-1]+rs[i])%md;
};

void cl(){
    int n;scanf("%d",&n);printf("Case #%d: %lld\n",++ct,rs[n]);
};

int main(){
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
#endif
    int t;scanf("%d",&t);for(_init();t--;cl());
    return 0;
};

猜你喜欢

转载自blog.csdn.net/u012345506/article/details/86292618
今日推荐