「SPOJ 5971」LCMSUM

题目链接:https://www.luogu.org/problemnew/show/SP5971

Description

求解

A n s w e r = i = 1 n lcm ( i , n )

Solution

易得原式即

i = 1 n i n gcd ( i , n )

根据 gcd ( a , n ) = 1 时一定有 gcd ( n a , n ) = 1 ,可将原式化为

1 2 ( i = 1 n 1 i n gcd ( i , n ) + i = n 1 1 i n gcd ( i , n ) ) + n

上述式子中括号内的两个 对应的项相等,故又可以化为

1 2 i = 1 n 1 n 2 gcd ( i , n ) + n

可以将相同的 gcd ( i , n ) 合并在一起计算,故只需要统计 gcd ( i , n ) = d 的个数。当 gcd ( i , n ) = d 时, gcd ( i d , n d ) = 1 ,所以 gcd ( i , n ) = d 的个数有 φ ( n d ) 个。

故答案为

1 2 d | n n 2 φ ( n d ) d + n

变换求和顺序,设 d = n d ,式子化为

1 2 n d | n d φ ( d ) + n

g ( n ) = d | n d φ ( d ) ,已知 g 为积性函数,于是可以 Θ ( n ) 预处理。最后枚举 d ,统计贡献即可。

时间复杂度

  • 欧拉筛预处理: Θ ( n )
  • 枚举因数并计算贡献: Θ ( n log n )

代码

#include <cstdio>
const int N=1000000;
int tot,p[N+5],phi[N+5];
long long ans[N+5];
bool flg[N+5];

void solve() {
    phi[1]=1;
    for(int i=2;i<=N;++i) {
        if(!flg[i]) p[++tot]=i,phi[i]=i-1;
        for(int j=1;j<=tot&&i*p[j]<=N;++j) {
            flg[i*p[j]]=1;
            if(i%p[j]==0) {
                phi[i*p[j]]=phi[i]*p[j];
                break;
            }
            phi[i*p[j]]=phi[i]*(p[j]-1);
        }
    }
    for(int i=1;i<=N;++i) {
        for(int j=1;i*j<=N;++j) {
            ans[i*j]+=1LL*j*phi[j]/2;
        }
    }
    for(int i=1;i<=N;++i) ans[i]=1LL*i*ans[i]+i;
}
int main() {
    int T,n;
    solve();
    for(scanf("%d",&T);T;--T) {
        scanf("%d",&n);
        printf("%lld\n",ans[n]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/hydingsy/article/details/81783997