51nod1188最大公约数之和V2(欧拉函数+线性筛)

本文详细解析了51nod1188题目的解题思路,通过数学推导,将原问题转化为求解两个积性函数的Dirichlet卷积,并给出了线性筛和Dirichlet卷积两种解法的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:51nod1188.
题目大意:给定一个数 n n n,求:
∑ i = 1 n ∑ j = i + 1 n g c d ( i , j ) \sum_{i=1}^{n}\sum_{j=i+1}^{n}gcd(i,j) i=1nj=i+1ngcd(i,j)

1 ≤ n ≤ 5 ∗ 1 0 6 1\leq n\leq 5*10^6 1n5106,数据组数 ≤ 5 ∗ 1 0 4 \leq 5*10^4 5104.

直接推导下去:
∑ i = 1 n ∑ j = i + 1 n g c d ( i , j ) = ∑ i = 1 n ∑ j = 1 i g c d ( i , j ) − ∑ i = 1 n i = ∑ i = 1 n ∑ j = 1 i g c d ( i , j ) − n ( n + 1 ) 2 \sum_{i=1}^{n}\sum_{j=i+1}^{n}gcd(i,j)\\ =\sum_{i=1}^{n}\sum_{j=1}^{i}gcd(i,j)-\sum_{i=1}^{n}i\\ =\sum_{i=1}^{n}\sum_{j=1}^{i}gcd(i,j)-\frac{n(n+1)}{2} i=1nj=i+1ngcd(i,j)=i=1nj=1igcd(i,j)i=1ni=i=1nj=1igcd(i,j)2n(n+1)

到这一步我们开始推导前半个式子:
∑ i = 1 n ∑ j = 1 i g c d ( i , j ) = ∑ i = 1 n ∑ k = 1 i k ∗ ∑ j = 1 i [ g c d ( i , j ) = k ] \sum_{i=1}^{n}\sum_{j=1}^{i}gcd(i,j)\\ =\sum_{i=1}^{n}\sum_{k=1}^{i}k*\sum_{j=1}^{i}[gcd(i,j)=k] i=1nj=1igcd(i,j)=i=1nk=1ikj=1i[gcd(i,j)=k]

m = i k m=\frac{i}{k} m=ki,那么我们就可以把式子变为:
∑ i = 1 n ∑ j = 1 i g c d ( i , j ) = ∑ i = 1 n ∑ k ∣ i k ∗ ∑ j = 1 m [ g c d ( j , m ) = 1 ] = ∑ i = 1 n ∑ k ∣ i k ϕ ( m ) \sum_{i=1}^{n}\sum_{j=1}^{i}gcd(i,j)\\ =\sum_{i=1}^{n}\sum_{k|i}k*\sum_{j=1}^{m}[gcd(j,m)=1]\\ =\sum_{i=1}^{n}\sum_{k|i}k\phi(m) i=1nj=1igcd(i,j)=i=1nkikj=1m[gcd(j,m)=1]=i=1nkikϕ(m)

m m m代回式子中,即可得到:
∑ i = 1 n ∑ j = 1 i g c d ( i , j ) = ∑ i = 1 n ∑ k ∣ i k ϕ ( i k ) \sum_{i=1}^{n}\sum_{j=1}^{i}gcd(i,j)=\sum_{i=1}^{n}\sum_{k|i}k\phi( \frac{i}{k}) i=1nj=1igcd(i,j)=i=1nkikϕ(ki)

也就是说:
∑ i = 1 n ∑ j = i + 1 n g c d ( i , j ) = ∑ i = 1 n ∑ k ∣ i k ϕ ( i k ) − n ( n + 1 ) 2 \sum_{i=1}^{n}\sum_{j=i+1}^{n}gcd(i,j)= \sum_{i=1}^{n}\sum_{k|i}k\phi(\frac{i}{k})-\frac{n(n+1)}{2} i=1nj=i+1ngcd(i,j)=i=1nkikϕ(ki)2n(n+1)

仔细一思考,发现我们得到的式子大概是这样的:
∑ i = 1 n ( ε × ϕ ) ( i ) \sum_{i=1}^{n}(\varepsilon \times \phi)(i) i=1n(ε×ϕ)(i)

这不就是两个积性函数的dirichlet卷积嘛,直接用dirichlet卷积预处理,然后前缀和一下就可以做到 O ( n log ⁡ n + T ) O(n\log n+T) O(nlogn+T)解决这个问题.

但是我们知道两个积性函数的dirichlet卷积也是一个积性函数,而一般积性函数是可以用线性筛筛的,如果用线性筛预处理的话这道题就可以做到 O ( n + T ) O(n+T) O(n+T)解决了.

那么怎么线性筛呢?我们可以构造一个函数 f f f
f ( i ) = ∑ k ∣ i i k ϕ ( k ) f(i)=\sum_{k|i}\frac{i}{k}\phi(k) f(i)=kikiϕ(k)

考虑使用线性筛筛这个函数 f f f了:
1.当 i i i为素数时, f ( i ) = 2 i − 1 f(i)=2i-1 f(i)=2i1.
2.当 g c d ( i , p r [ j ] ) = 1 gcd(i,pr[j])=1 gcd(i,pr[j])=1时,由于这个函数是积性函数,所以 f ( i ∗ p r [ j ] ) = f ( i ) f ( p r [ j ] ) f(i*pr[j])=f(i)f(pr[j]) f(ipr[j])=f(i)f(pr[j]).
3.当 p r [ j ] ∣ i pr[j]|i pr[j]i时,那么:
f ( i ∗ p r [ j ] ) = ∑ k ∣ i ∗ p r [ j ] i ∗ p r [ j ] k ϕ ( k ) f(i*pr[j])=\sum_{k|i*pr[j]}\frac{i*pr[j]}{k}\phi(k) f(ipr[j])=kipr[j]kipr[j]ϕ(k)

我们设 m u l [ i ] mul[i] mul[i]表示 i i i的所有最小素因子之积,那么:
f ( i ∗ p r [ j ] ) = ∑ k ∣ i i ∗ p r [ j ] k ϕ ( k ) + ∑ k ∣ i m u l [ i ] i ∗ p r [ j ] k ∗ m u l [ i ] ϕ ( k ∗ m u l [ i ] ) = p r [ j ] ∗ f ( i ) + ∑ k ∣ i m u l [ i ] i ∗ p r [ j ] k ∗ m u l [ i ] ϕ ( k ) ∗ ϕ ( m u l [ i ] ) = p r [ j ] ∗ f ( i ) + ∑ k ∣ i m u l [ i ] i ∗ p r [ j ] k ∗ m u l [ i ] ϕ ( k ) ∗ m u l [ i ] ∗ p r [ j ] − 1 p r [ j ] = p r [ j ] ∗ f ( i ) + ( p r [ j ] − 1 ) ∑ k ∣ i m u l [ i ] i k ϕ ( k ) = p r [ j ] ∗ f ( i ) + m u l [ i ] ( p r [ j ] − 1 ) ∑ k ∣ i m u l [ i ] i m u l [ i ] ∗ k ϕ ( k ) = p r [ j ] ∗ f ( i ) + m u l [ i ] ( p r [ j ] − 1 ) f ( i m u l [ i ] ) f(i*pr[j])=\sum_{k|i}\frac{i*pr[j]}{k}\phi(k)+\sum_{k|\frac{i}{mul[i]}}\frac{i*pr[j]}{k*mul[i]}\phi(k*mul[i])\\ =pr[j]*f(i)+\sum_{k|\frac{i}{mul[i]}}\frac{i*pr[j]}{k*mul[i]}\phi(k)*\phi(mul[i])\\ =pr[j]*f(i)+\sum_{k|\frac{i}{mul[i]}}\frac{i*pr[j]}{k*mul[i]}\phi(k)*mul[i]*\frac{pr[j]-1}{pr[j]}\\ =pr[j]*f(i)+(pr[j]-1)\sum_{k|\frac{i}{mul[i]}}\frac{i}{k}\phi(k)\\ =pr[j]*f(i)+mul[i](pr[j]-1)\sum_{k|\frac{i}{mul[i]}}\frac{i}{mul[i]*k}\phi(k)\\ =pr[j]*f(i)+mul[i](pr[j]-1)f(\frac{i}{mul[i]}) f(ipr[j])=kikipr[j]ϕ(k)+kmul[i]ikmul[i]ipr[j]ϕ(kmul[i])=pr[j]f(i)+kmul[i]ikmul[i]ipr[j]ϕ(k)ϕ(mul[i])=pr[j]f(i)+kmul[i]ikmul[i]ipr[j]ϕ(k)mul[i]pr[j]pr[j]1=pr[j]f(i)+(pr[j]1)kmul[i]ikiϕ(k)=pr[j]f(i)+mul[i](pr[j]1)kmul[i]imul[i]kiϕ(k)=pr[j]f(i)+mul[i](pr[j]1)f(mul[i]i)

很明显 m u l [ i ] mul[i] mul[i]是可以在线性筛的时候顺便筛出来的,所以我们就可以愉快的 O ( n + T ) O(n+T) O(n+T)AC这道题啦.

线性筛代码如下:

#include<bits/stdc++.h>
  using namespace std;
 
#define Abigail inline void
typedef long long LL;
 
const int N=5000000;
 
int pr[N+9],b[N+9],tp;
LL mul[N+9],f[N+9],phi[N+9],F[N+9];
 
void sieve(int n){
  for (int i=2;i<=n;++i) b[i]=1;
  mul[1]=1;f[1]=1;phi[1]=1;
  int v;
  for (int i=2;i<=n;++i){
    if (b[i]){
      pr[++tp]=i;
      phi[i]=LL(i-1);
      mul[i]=LL(i);
      f[i]=LL(2*i-1);
    }
    for (int j=1;j<=tp&&i*pr[j]<=n;++j){
      b[v=i*pr[j]]=0;
      if (i%pr[j]==0){
        mul[v]=mul[i]*pr[j];
        phi[v]=phi[i]*pr[j];
        f[v]=f[i]*pr[j]+mul[i]*LL(pr[j]-1)*f[LL(i)/mul[i]];
        break;
      }
      mul[v]=LL(pr[j]);
      phi[v]=phi[i]*phi[pr[j]];
      f[v]=f[i]*f[pr[j]];
    }
  }
  for (int i=1;i<=n;++i)
    F[i]=f[i]+F[i-1];
}
 
Abigail work(){
  sieve(N);
}
 
Abigail getans(){
  int T,n;
  scanf("%d",&T);
  while (T--){
    scanf("%d",&n);
    printf("%lld\n",F[n]-LL(n)*LL(n+1)/2LL);
  }
}
 
int main(){
  work();
  getans();
  return 0;
} 

emmm…顺便也写了一个dirichlet卷积的代码,如果实在看不懂线性筛做法的就参考dirichlet卷积的代码吧:

#include<bits/stdc++.h>
  using namespace std;
 
#define Abigail inline void
typedef long long LL;
 
const int N=5000000;
 
int pr[N+9],b[N+9],tp;
LL phi[N+9],F[N+9];
 
void sieve(int n){
  for (int i=2;i<=n;++i) b[i]=1;
  phi[1]=1;
  for (int i=2;i<=n;++i){
    if (b[i]) pr[++tp]=i,phi[i]=LL(i-1);
    for (int j=1;j<=tp&&pr[j]*i<=n;++j){
      b[i*pr[j]]=0;
      if (i%pr[j]) phi[i*pr[j]]=phi[i]*phi[pr[j]];
      else {phi[i*pr[j]]=phi[i]*pr[j];break;}
    }
  }
}
 
void dirichlet(int n){
  for (int i=1;i<=n;++i)
    for (int j=1;i*j<=n;++j)
      F[i*j]+=phi[i]*j;
  for (int i=1;i<=n;++i)
    F[i]+=F[i-1];
}
 
Abigail work(){
  sieve(N);
  dirichlet(N);
}
 
Abigail getans(){
  int T,n;
  scanf("%d",&T);
  while (T--){
    scanf("%d",&n);
    printf("%lld\n",F[n]-LL(n)*LL(n+1)/2LL);
  }
}
 
int main(){
  work();
  getans();
  return 0;
}

貌似也有一个除法分块的做法可以做到 O ( n + T n ) O(n+T\sqrt{n}) O(n+Tn ),比较慢但是好推一些,原理与上面的式子其实也差不多,这里就不写了.

基于开源大模型的教学实训智能体软件,帮助教师生成课前备课设计、课后检测问答,提升效率与效果,提供学生全时在线练习与指导,实现教学相长。 智能教学辅助系统 这是一个智能教学辅助系统的前端项目,基于 Vue3+TypeScript 开发,使用 Ant Design Vue 作为 UI 组件库。 功能模块 用户模块 登录/注册功能,支持学生教师角色 毛玻璃效果的登录界面 教师模块 备课与设计:根据课程大纲自动设计教学内容 考核内容生成:自动生成多样化考核题目及参考答案 学情数据分析:自动化检测学生答案,提供数据分析 学生模块 在线学习助手:结合教学内容解答问题 实时练习评测助手:生成随练题目并纠错 管理模块 用户管理:管理员/教师/学生等用户基本管理 课件资源管理:按学科列表管理教师备课资源 大屏概览:使用统计、效率指数、学习效果等 技术栈 Vue3 TypeScript Pinia 状态管理 Ant Design Vue 组件库 Axios 请求库 ByteMD 编辑器 ECharts 图表库 Monaco 编辑器 双主题支持(专业科技风/暗黑风) 开发指南 # 安装依赖 npm install # 启动开发服务器 npm run dev # 构建生产版本 npm run build 简介 本项目旨在开发一个基于开源大模型的教学实训智能体软件,帮助教师生成课前备课设计、课后检测问答,提升效率与效果,提供学生全时在线练习与指导,实现教学相长。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值