SP5971 LCMSUM - LCM Sum(欧拉函数,公式推导)

SP5971 LCMSUM - LCM Sum

题意:求在这里插入图片描述

推式子

∑ i = 1 n l c m ( i , n ) ∑ i = 1 n i n g c d ( i , n ) n ∑ i = 1 n i g c d ( i , n ) n ∑ d ∣ n ∑ i = 1 n i d [ g c d ( i , n ) = d ] n ∑ d ∣ n ∑ i = 1 n d i [ g c d ( i , n d ) = 1 ] n ∑ d ∣ n ( ϕ ( d ) + [ d = 1 ] ) × d 2 \sum_{i=1}^nlcm(i,n)\\ \sum_{i=1}^n\frac {in}{gcd(i,n)}\\ n\sum_{i = 1} ^{n} \frac{i}{gcd(i, n)}\\ n\sum_{d \mid n} \sum_{i = 1} ^{n} \frac{i}{d}[gcd(i, n) = d]\\ n\sum_{d \mid n} \sum_{i = 1} ^{\frac{n}{d}} i[gcd(i, \frac{n}{d}) = 1]\\ n\sum_{d \mid n} \frac{(\phi(d) + [d = 1]) \times d}{2} i=1nlcm(i,n)i=1ngcd(i,n)inni=1ngcd(i,n)indni=1ndi[gcd(i,n)=d]ndni=1dni[gcd(i,dn)=1]ndn2(ϕ(d)+[d=1])×d

第一个式子就是问题;
第二个式子就是把 l c m lcm lcm拆开;
第三个式子就是把常数n提出去;
第四个式子就是枚举一下n的全部因子,就可以化成第四个式子的样子;
第五个式子就是把d从 [ [ g c d ( i , n ) = d ] [[gcd(i,n)=d] [[gcd(i,n)=d]里面提出去,然后取值范围,枚举的数 i d \frac id di变成 i i i [ g c d ( i , n ) = d ] [gcd(i,n)=d] [gcd(i,n)=d]变成 [ g c d ( i , n d ) = 1 ] [gcd(i,\frac nd)=1] [gcd(i,dn)=1]
第六个式子就是利用欧拉函数的一个性质: 如 果 g c d ( i , n ) = 1 , 则 g c d ( n − i , n ) = 1 ( i ≠ 1 ) 如果gcd(i,n)=1,则gcd(n-i,n)=1(i\neq1) gcd(i,n)=1gcd(ni,n)=1(i=1),然后就可以化成第六个式子了;
结束

C o d e Code Code

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10;
typedef long long ll;
ll st[N], p[N], phi[N], sum[N], ans[N], tot;
//phi:欧拉函数,sum函数第六个公式中的欧拉函数phi*d,ans是存放答案的数组;
void init() {
    
    
    phi[1] = 1, st[1] = 1, sum[1] = 1;//sum[1]=1,把d=1的情况考虑了进去
    for(int i=2; i<N; i++) {
    
    
        if(!st[i]) p[tot++] = i, phi[i] = i-1, sum[i] = 1ll*phi[i]*i/2;
        for(int j=0; j<tot&&i*p[j]<N; j++) {
    
    
            st[i*p[j]] = 1;
            if(i % p[j] == 0) {
    
    
                phi[i*p[j]] = phi[i]*p[j];
                sum[i*p[j]] = 1ll*phi[i*p[j]]*(i*p[j])/2; 
                break;
            }
            phi[i*p[j]] = phi[i]*(p[j]-1);
            sum[i*p[j]] = 1ll*phi[i*p[j]]*(i*p[j])/2; 
        }
    }
    //类埃氏筛,把n的全部因子d加起来ans[n]+=sum[d];
    for(int i=1; i<N; i++) {
    
    
        for(int j=i; j<N; j+=i)
        ans[j] += sum[i];
    }
}
inline ll read() {
    
    //快读
    ll x = 0, f = 1; char c = getchar();
    while(c < '0' || c > '9') {
    
    
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') {
    
    
        x = (x << 1) + (x << 3) + (c ^ 48);
        c = getchar();
    }
    return x * f;
}

int main() {
    
    
    init();//初始化
    ll t;
    t = read();
    while(t--) {
    
    
        int n;
        n = read();
        printf("%lld\n", ans[n]*n);
    }
    return 0;
}

End

猜你喜欢

转载自blog.csdn.net/weixin_45363113/article/details/111086958
lcm