P1891 疯狂 LCM

疯狂 LCM

题意即求:

\[\sum _ { i = 1 } ^ { n } \operatorname{lcm} ( i , n ) \]

其中 \(T\le 3 \times 10 ^5\)\(n \le 10 ^ 6\)

直接推导:

\[\begin{aligned} & \sum _ { i = 1 } ^ { n } \operatorname{lcm} ( i , n ) \\ = & \sum _ { i = 1 } ^ { n } \dfrac{ i n }{\gcd ( i , n )} \\ = & \sum _ {d \mid n } n\sum _ { i = 1 } ^ { n } \dfrac{ i }{ d } \left[ \gcd ( i , n ) = d \right] \\ = & \sum _ {d \mid n } n\sum _ { i = 1 } ^ { n / d } i \left[ \gcd ( i , n / d ) = 1 \right] \\ = & \sum _ {d \mid n } n\sum _ { i = 1 } ^ { n / d } i \sum _ { k \mid i , k \mid n/d} \mu ( k ) \\ = & n\sum _ {d \mid n } \sum _ { k \mid n/d} \mu ( k ) k \sum _ { i = 1 } ^ { n / kd } i \\ = & n\sum _ {T \mid n } \sum _ { d \mid T } \mu ( k ) k \sum _ { i = 1 } ^ { n / T } i \end{aligned} \]

后面整体都可以 \(O( n \ln n )\) 预处理。

时间复杂度 \(O(n \ln n + T)\)

代码:

#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
namespace Ehnaev{
  inline ll read() {
    ll ret=0,f=1;char ch=getchar();
    while(ch<48||ch>57) {if(ch==45) f=-f;ch=getchar();}
    while(ch>=48&&ch<=57) {ret=(ret<<3)+(ret<<1)+ch-48;ch=getchar();}
    return ret*f;
  }
  inline void write(ll x) {
    static char buf[22];static ll len=-1;
    if(x>=0) {do{buf[++len]=x%10+48;x/=10;}while(x);}
    else {putchar(45);do{buf[++len]=-(x%10)+48;x/=10;}while(x);}
    while(len>=0) putchar(buf[len--]);
  }
}using Ehnaev::read;using Ehnaev::write;
inline void writeln(ll x) {write(x);putchar(10);}

const ll N=1e6;

ll T,n,cnt;
ll prime[N+5],f[N+5],mu[N+5],g[N+5],ans[N+5];
bool ff[N+5];

inline void Init() {
  ff[1]=1;mu[1]=1;
  for(ll i=2;i<=N;i++) {
    if(!ff[i]) {prime[++cnt]=i;mu[i]=-1;}
    for(ll j=1;j<=cnt&&i*prime[j]<=N;j++) {
      ff[i*prime[j]]=1;
      if(i%prime[j]==0) {mu[i*prime[j]]=0;break;}
      mu[i*prime[j]]=-mu[i];
    }
  }
  for(ll i=1;i<=N;i++) {f[i]=i*mu[i];}
  for(ll i=1;i<=cnt;i++) {
    for(ll j=1;j*prime[i]<=N;j++) {
      f[j*prime[i]]+=f[j];
    }
  }
  for(ll i=1;i<=N;i++) {g[i]=i*(i+1)/2;}
  for(ll i=1;i<=N;i++) {
    for(ll j=i,cn=1;j<=N;j+=i,cn++) {
      ans[j]+=f[i]*g[cn];
    }
  }
  for(ll i=1;i<=N;i++) ans[i]*=i;
}

int main() {

  T=read();Init();

  while(T--) {
    n=read();
    writeln(ans[n]);
  }

  return 0;
}
posted @ 2023-02-07 16:35  Aryper  阅读(25)  评论(0编辑  收藏  举报