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

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

题目: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 ),比较慢但是好推一些,原理与上面的式子其实也差不多,这里就不写了.

【无人机】基于改进粒子群算法的无人机路径规划研究[遗传算法、粒子群算法进行比较](Matlab代码实现)内容概要:本文围绕基于改进粒子群算法的无人机路径规划展开研究,重点探讨了在复杂环境中利用改进粒子群算法(PSO)实现无人机三维路径规划的方法,并将其与遗传算法(GA)、标准粒子群算法等传统优化算法进行对比分析。研究内容涵盖路径规划的多目标优化、避障策略、航路点约束以及算法收敛性寻优能力的评估,所有实验均通过Matlab代码实现,提供了完整的仿真验证流程。文章还提到了多种智能优化算法在无人机路径规划中的应用比较,突出了改进PSO在收敛速度全局寻优方面的优势。; 适合人群:具备一定Matlab编程基础优化算法知识的研究生、科研人员及从事无人机路径规划、智能优化算法研究的相关技术人员。; 使用场景及目标:①用于无人机在复杂地形或动态环境下的三维路径规划仿真研究;②比较不同智能优化算法(如PSO、GA、蚁群算法、RRT等)在路径规划中的性能差异;③为多目标优化问题提供算法选型改进思路。; 阅读建议:建议读者结合文中提供的Matlab代码进行实践操作,重点关注算法的参数设置、适应度函数设计及路径约束处理方式,同时可参考文中提到的多种算法对比思路,拓展到其他智能优化算法的研究与改进中。
### 关于51Nod 3100 上台阶问题的C++解法 #### 题目解析 该题目通常涉及斐波那契数列的应用。假设每次可以走一步或者两步,那么到达第 \( n \) 层台阶的方法总数等于到达第 \( n-1 \)第 \( n-2 \) 层方法数之和。 此逻辑可以通过动态规划来解决,并且为了防止数值过大,需要对结果取模操作(如 \( \% 100003 \)[^1])。以下是基于上述思路的一个高效实现: ```cpp #include <iostream> using namespace std; const int MOD = 100003; long long f[100010]; int main() { int n; cin >> n; // 初始化前两项 f[0] = 1; // 到达第0层有1种方式(不移动) f[1] = 1; // 到达第1层只有1种方式 // 动态规划计算f[i] for (int i = 2; i <= n; ++i) { f[i] = (f[i - 1] + f[i - 2]) % MOD; } cout << f[n] << endl; return 0; } ``` 以上代码通过数组 `f` 存储每层台阶的结果,利用循环逐步填充至目标层数 \( n \),并最终输出结果。 --- #### 时间复杂度分析 由于仅需一次线性遍历即可完成所有状态转移,时间复杂度为 \( O(n) \)。空间复杂度同样为 \( O(n) \),但如果优化存储,则可进一步降低到 \( O(1) \): ```cpp #include <iostream> using namespace std; const int MOD = 100003; int main() { int n; cin >> n; long long prev2 = 1, prev1 = 1, current; if (n == 0 || n == 1) { cout << 1 << endl; return 0; } for (int i = 2; i <= n; ++i) { current = (prev1 + prev2) % MOD; prev2 = prev1; prev1 = current; } cout << prev1 << endl; return 0; } ``` 在此版本中,只保留最近两个状态变量 (`prev1`, `prev2`) 来更新当前值,从而节省内存开销。 --- #### 输入输出说明 输入部分接受单个整数 \( n \),表示台阶数量;程序会返回从地面走到第 \( n \) 层的不同路径数目,结果经过指定模运算处理以适应大范围数据需求。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值