目录
- 前置知识
 - 一些约定
 - 数论分块
 - 狄利克雷卷积
 - 定义
 - 一些常见的狄利克雷卷积
 
- 莫比乌斯反演
 - 莫比乌斯函数的性质/莫比乌斯变换
 
- 例题讲解
 - 公约数的和
 - 题目背景
 - 题目描述
 - 输入格式
 - 输出格式
 - 样例 #1
 - 样例输入 #1
 - 样例输出 #1
 
- 提示
 - 数据规模与约定
 
- 思路
 
- AC代码
 - [HAOI2011] Problem b
 - 题目描述
 - 输入格式
 - 输出格式
 - 样例 #1
 - 样例输入 #1
 - 样例输出 #1
 
- 提示
 
- 思路
 - AC代码
 - [国家集训队] Crash的数字表格 / JZPTAB
 - 题目描述
 - 输入格式
 - 输出格式
 - 样例 #1
 - 样例输入 #1
 - 样例输出 #1
 
- 提示
 - 样例输入输出 1 解释
 - 数据规模与约定
 
- 思路
 - AC代码
 
- [SDOI2015] 约数个数和
 - 题目描述
 - 输入格式
 - 输出格式
 - 样例 #1
 - 样例输入 #1
 - 样例输出 #1
 
- 提示
 - 思路
 - AC代码
 - [SDOI2008] 仪仗队
 - 题目描述
 - 输入格式
 - 输出格式
 - 样例 #1
 - 样例输入 #1
 - 样例输出 #1
 
- 提示
 
- 思路
 - AC代码
 - Product
 - 题目背景
 - 题目描述
 - 输入格式
 - 输出格式
 - 样例 #1
 - 样例输入 #1
 - 样例输出 #1
 
- 提示
 
- 思路
 - AC代码
 
前置知识
一些约定
•[A]:当且仅当表达式 A 为真时 [A] = 1,否则 [A] = 0.
 •gcd(x, y) 或 (x, y):表示 x 和 y 的最大公因数.
 •lcm(x, y):表示 x 和 y 的最小公倍数.
 •d | n:表示 d 整除 n.
 •d ∤ n:表示 d 不整除 n.
 • 
     
      
       
       
         [ 
        
        
         
          
           
           
             n 
            
           
          
         
         
          
           
           
             d 
            
           
          
         
        
       
         ] 
        
       
      
        \begin{bmatrix}n\\d \end{bmatrix} 
       
      
    [nd]:下取整符号.
 • 正体、粗体或希腊字母,如 1, F, σ, d 等:表示数论函数.
 • 其他字母如 i, j, d, g, T 等:表示数字
数论分块
问题 1:给定正整数 n,求 
     
      
       
       
         n 
        
        
        
          ∑ 
         
         
         
           i 
          
         
           = 
          
         
           1 
          
         
        
          n 
         
        
        
        
          [ 
         
         
          
           
            
            
              n 
             
            
           
          
          
           
            
            
              i 
             
            
           
          
         
        
          ] 
         
        
       
      
        n\sum\limits^n_{i=1}\begin{bmatrix}n\\i\end{bmatrix} 
       
      
    ni=1∑n[ni]?
 不难发现  
     
      
       
       
         [ 
        
        
         
          
           
           
             n 
            
           
          
         
         
          
           
           
             i 
            
           
          
         
        
       
         ] 
        
       
      
        \begin{bmatrix}n\\i\end{bmatrix} 
       
      
    [ni]的值呈块状分布,每一块内 
     
      
       
       
         [ 
        
        
         
          
           
           
             n 
            
           
          
         
         
          
           
           
             i 
            
           
          
         
        
       
         ] 
        
       
      
        \begin{bmatrix}n\\i\end{bmatrix} 
       
      
    [ni]的值相同,且每
 个块最后位置均为 
     
      
       
        
        
          n 
         
         
         
           [ 
          
          
           
            
             
             
               n 
              
             
            
           
           
            
             
             
               i 
              
             
            
           
          
         
           ] 
          
         
        
       
      
        \frac{n}{\begin{bmatrix}n\\i\end{bmatrix}} 
       
      
    [ni]n
 ,所以可以计算,时间复杂度 O(√n)。
 求 1 到 n 的 µ 值,可以使用线性筛做到 O(n)。
mu[1] = 1;
for(int i = 2; i <= n; i++) {
if(!not_prime[i]) prime[++tot] = i, mu[i] = -1;
for(int j = 1; j <= tot && i*prime[j] <= n; j++) {
not_prime[i*prime[j]] = true;
if(i%prime[j] == 0) break;
mu[i*prime[j]] = -mu[i];
}
}
 
也可以打包带走连着 φ 一起筛:
mu[1] = phi[1] = 1;
for(int i = 2; i <= n; i++) {
if(!not_prime[i]) prime[++tot] = i,
mu[i] = -1, phi[i] = i-1;
for(int j = 1; j <= tot && i*prime[j] <= n; j++) {
not_prime[i*prime[j]] = true;
if(i%prime[j] == 0) {
phi[i*prime[j]] = phi[i] * prime[j];
break;
}
mu[i*prime[j]] = -mu[i];
phi[i*prime[j]] = phi[i] * phi[prime[j]];
}
}
 
狄利克雷卷积
卷积、旋积或褶积(英语:Convolution)是通过两个函数f和g生成第三个函数的一种数学运算,其本质是一种特殊的积分变换,表征函数f与g经过翻转和平移的重叠部分函数值乘积对重叠长度的积分。(源于:百度百科)
 上面是百度百科给的定义,第一次接触的时候也是一头雾水,就看懂了一句:卷积是一种数学运算,单着一句就够用了
 卷积就是一种数学运算
定义
若数论函数 F, G, H 满足: 
     
      
       
       
         F 
        
       
         ( 
        
       
         n 
        
       
         ) 
        
       
         = 
        
        
        
          ∑ 
         
         
         
           d 
          
         
           ∣ 
          
         
           n 
          
         
        
       
         G 
        
       
         ( 
        
       
         d 
        
       
         ) 
        
       
         H 
        
       
         ( 
        
        
        
          n 
         
        
          d 
         
        
       
         ) 
        
       
      
        F(n)=\sum \limits _{d|n}G(d)H(\frac{n}{d}) 
       
      
    F(n)=d∣n∑G(d)H(dn)
 则称 F 是 G 和 H 的狄利克雷卷积,记作 F = G ∗ H
一些常见的狄利克雷卷积
•φ ∗ 1 = id:即  
     
      
       
        
        
          ∑ 
         
         
         
           d 
          
         
           ∣ 
          
         
           n 
          
         
        
       
         φ 
        
       
         ( 
        
       
         d 
        
       
         ) 
        
       
         = 
        
       
         n 
        
       
         . 
        
       
      
        \sum \limits _{d|n}φ(d) = n. 
       
      
    d∣n∑φ(d)=n.
 • 对于任意数论函数 F,都有 F ∗ ϵ = F.
 • 
     
      
       
       
         i 
        
        
        
          d 
         
        
          k 
         
        
       
         ∗ 
        
       
         1 
        
       
         = 
        
        
        
          σ 
         
        
          k 
         
        
       
         . 
        
       
      
        id^k∗ 1 = σ_k. 
       
      
    idk∗1=σk.
 •µ ∗ 1 = ϵ
 也就是说,µ 实际上是 1 的逆元。
莫比乌斯反演
莫比乌斯函数的性质/莫比乌斯变换
因为 µ 是 1 的逆元,对于任意数论函数 F 有:
 F ∗ 1 = G ⇐⇒ G ∗ µ = F
 也就是说:
 •id ∗ µ = φ.
 • 
     
      
       
        
        
          σ 
         
        
          k 
         
        
       
         ∗ 
        
       
         µ 
        
       
         = 
        
       
         i 
        
        
        
          d 
         
        
          k 
         
        
       
         . 
        
       
      
        σ_k ∗ µ = id^k. 
       
      
    σk∗µ=idk.
 •µ ∗ 1 = ϵ.
 然后……就结束了
 莫比乌斯反演的精髓:数学推导
例题讲解
公约数的和
题目背景
有一天,TIBBAR 和 LXL 比赛谁先算出 1 ∼ n 1 \sim n 1∼n 这 n n n 个数中每任意两个不同的数的最大公约数的和。LXL 还在敲一个复杂而冗长的程序,争取能在 100 s 100s 100s 内出解。而 TIBBAR 则直接想 1 s 1s 1s 秒过而获得完胜,请你帮他完成这个任务。
题目描述
给定  
     
      
       
       
         n 
        
       
      
        n 
       
      
    n,求
  
      
       
        
         
         
           ∑ 
          
          
          
            i 
           
          
            = 
           
          
            1 
           
          
         
           n 
          
         
         
         
           ∑ 
          
          
          
            j 
           
          
            = 
           
          
            i 
           
          
            + 
           
          
            1 
           
          
         
           n 
          
         
        
          gcd 
         
        
           
         
        
          ( 
         
        
          i 
         
        
          , 
         
        
          j 
         
        
          ) 
         
        
       
         \sum_{i = 1}^n \sum_{j = i + 1}^n \gcd(i, j) 
        
       
     i=1∑nj=i+1∑ngcd(i,j)
其中 gcd  ( i , j ) \gcd(i, j) gcd(i,j) 表示 i i i 和 j j j 的最大公约数。
输入格式
输入只有一行一个整数,表示 n n n。
输出格式
输出一行一个整数表示答案。
样例 #1
样例输入 #1
10
 
样例输出 #1
67
 
提示
数据规模与约定
- 对于 40 % 40\% 40% 的数据,保证 n ≤ 2 × 1 0 3 n \leq 2 \times 10^3 n≤2×103。
 - 对于 100 % 100\% 100% 的数据,保证 2 ≤ n ≤ 2 × 1 0 6 2 \leq n \leq 2 \times 10^6 2≤n≤2×106。
 
思路



 
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e6+5;
ll p[N],n;ll phi[N];
bool notp[N];
void seive(ll n){
    phi[1] = 1;
    for(ll i=2;i<=n;++i) {
        if(!notp[i]) p[++p[0]] = i, phi[i] = i-1;
        for(ll j=1;j<=p[0] && i*p[j]<=n;++j) {
            notp[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(ll i=1;i<=n;++i) phi[i] += phi[i-1];
}
inline ll cal(ll n,ll m){
    ll ans = 0,r;
    for(ll i=1;i<=n;i=r+1) {
        r = min(n/(n/i), m/(m/i));
        ans += (phi[r]-phi[i-1]) * (n/i) * (m/i);
    }
    return ans;
}
int main() {
    cin>>n;
    seive(n);
    cout<<(cal(n,n)-n*(n+1)/2)/2<<endl;
}
 
[HAOI2011] Problem b
题目描述
对于给出的 n n n 个询问,每次求有多少个数对 ( x , y ) (x,y) (x,y),满足 a ≤ x ≤ b a \le x \le b a≤x≤b, c ≤ y ≤ d c \le y \le d c≤y≤d,且 gcd  ( x , y ) = k \gcd(x,y) = k gcd(x,y)=k, gcd  ( x , y ) \gcd(x,y) gcd(x,y) 函数为 x x x 和 y y y 的最大公约数。
输入格式
第一行一个整数 n n n,接下来 n n n 行每行五个整数,分别表示 a , b , c , d , k a,b,c,d,k a,b,c,d,k。
输出格式
共 n n n 行,每行一个整数表示满足要求的数对 ( x , y ) (x,y) (x,y) 的个数。
样例 #1
样例输入 #1
2
2 5 1 5 1
1 5 1 5 2
 
样例输出 #1
14
3
 
提示
对于 100 % 100\% 100% 的数据满足: 1 ≤ n , k ≤ 5 × 1 0 4 1 \le n,k \le 5 \times 10^4 1≤n,k≤5×104, 1 ≤ a ≤ b ≤ 5 × 1 0 4 1 \le a \le b \le 5 \times 10^4 1≤a≤b≤5×104, 1 ≤ c ≤ d ≤ 5 × 1 0 4 1 \le c \le d \le 5 \times 10^4 1≤c≤d≤5×104。
思路

 
AC代码
#include<bits/stdc++.h>
#define N 60010
using namespace std;
bool vis[N];
int prim[N],mu[N],sum[N],cnt,k;
inline void get_mu(int n)
{
    mu[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(!vis[i]){mu[i]=-1;prim[++cnt]=i;}
        for(int j=1;j<=cnt&&i*prim[j]<=n;j++)
        {
            vis[i*prim[j]]=1;
            if(i%prim[j]==0)break;
            else mu[i*prim[j]]=-mu[i];
        }
    }
    for(int i=1;i<=n;i++)sum[i]=sum[i-1]+mu[i];
}
inline long long calc(int a,int b)
{
    static int max_rep;
    static long long ans;
    max_rep=min(a,b);ans=0;
    for(int l=1,r;l<=max_rep;l=r+1)
    {
        r=min(a/(a/l),b/(b/l));
        ans+=(1ll*a/(1ll*l*k))*(1ll*b/(1ll*l*k))*(sum[r]-sum[l-1]);
    }
    return ans;
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
    int t;
    cin>>t;
    get_mu(50000);
    while(t--)
    {
        int a,b,c,d;
        cin>>a>>b>>c>>d>>k;
        cout<<calc(b,d)-calc(b,c-1)-calc(a-1,d)+calc(a-1,c-1)<<endl;
    }
    return 0;
}
 
[国家集训队] Crash的数字表格 / JZPTAB
题目描述
今天的数学课上,Crash 小朋友学习了最小公倍数(Least Common Multiple)。对于两个正整数 a a a 和 b b b, lcm ( a , b ) \text{lcm}(a,b) lcm(a,b) 表示能同时被 a a a 和 b b b 整除的最小正整数。例如, lcm ( 6 , 8 ) = 24 \text{lcm}(6, 8) = 24 lcm(6,8)=24。
回到家后,Crash 还在想着课上学的东西,为了研究最小公倍数,他画了一张 $ n \times m$ 的表格。每个格子里写了一个数字,其中第 i i i 行第 j j j 列的那个格子里写着数为 lcm ( i , j ) \text{lcm}(i, j) lcm(i,j)。
看着这个表格,Crash 想到了很多可以思考的问题。不过他最想解决的问题却是一个十分简单的问题:这个表格中所有数的和是多少。当 n n n 和 m m m 很大时,Crash 就束手无策了,因此他找到了聪明的你用程序帮他解决这个问题。由于最终结果可能会很大,Crash 只想知道表格里所有数的和对 20101009 20101009 20101009 取模后的值。
输入格式
输入包含一行两个整数,分别表示 n n n 和 m m m。
输出格式
输出一个正整数,表示表格中所有数的和对 20101009 20101009 20101009 取模后的值。
样例 #1
样例输入 #1
4 5
 
样例输出 #1
122
 
提示
样例输入输出 1 解释
该表格为:
| 1 1 1 | 2 2 2 | 3 3 3 | 4 4 4 | 5 5 5 | 
|---|---|---|---|---|
| 2 2 2 | 2 2 2 | 6 6 6 | 4 4 4 | 10 10 10 | 
| 3 3 3 | 6 6 6 | 3 3 3 | 12 12 12 | 15 15 15 | 
| 4 4 4 | 4 4 4 | 12 12 12 | 4 4 4 | 20 20 20 | 
数据规模与约定
- 对于 30 % 30\% 30% 的数据,保证 n , m ≤ 1 0 3 n, m \le 10^3 n,m≤103。
 - 对于 70 % 70\% 70% 的数据,保证 n , m ≤ 1 0 5 n, m \le 10^5 n,m≤105。
 - 对于 100 % 100\% 100% 的数据,保证 1 ≤ n , m ≤ 1 0 7 1\le n,m \le 10^7 1≤n,m≤107。
 
思路

 
 
 
 因此前半部分可以预处理出前缀和,这样 f(n, m) 就能数论分块
 求了. 因为原问题也可以数论分块,所以求解的复杂度为  
     
      
       
       
         O 
        
       
         ( 
        
        
        
          n 
         
         
         
           3 
          
         
           4 
          
         
        
       
         ) 
        
       
      
        O(n^{\frac{3} {4} }) 
       
      
    O(n43),证明过程略.
 但是由于需要预处理  
     
      
       
       
         µ 
        
       
         ( 
        
       
         d 
        
       
         ) 
        
        
        
          d 
         
        
          2 
         
        
       
      
        µ(d)d^2 
       
      
    µ(d)d2 的前缀和,瓶颈在线性筛和预处理,
 所以总复杂度是线性的 O(n)
AC代码
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=1e7+5,mod=20101009;
int n,m,mu[N],p[N/10],sum[N];
bool flg[N];
inline void init() {
    mu[1]=1;
    int tot=0,k=min(n,m);
    for(int i=2;i<=k;++i) {
        if(!flg[i]) p[++tot]=i,mu[i]=-1;
        for(int j=1;j<=tot&&i*p[j]<=k;++j) {
            flg[i*p[j]]=1;
            if(i%p[j]==0) {mu[i*p[j]]=0;break;}
            mu[i*p[j]]=-mu[i];
        }
    }
    for(int i=1;i<=k;++i) sum[i]=(sum[i-1]+1LL*i*i%mod*(mu[i]+mod))%mod;
}
inline int Sum(int x,int y) {
    return (1LL*x*(x+1)/2%mod)*(1LL*y*(y+1)/2%mod)%mod;
}
inline int func(int x,int y) {
    int res=0;
    for(int i=1,j;i<=min(x,y);i=j+1) {
        j=min(x/(x/i),y/(y/i));
        res=(res+1LL*(sum[j]-sum[i-1]+mod)*Sum(x/i,y/i)%mod)%mod;
    }
    return res;
}
inline int solve(int x,int y) {
    int res=0;
    for(int i=1,j;i<=min(x,y);i=j+1) {
        j=min(x/(x/i),y/(y/i));
        res=(res+1LL*(j-i+1)*(i+j)/2%mod*func(x/i,y/i)%mod)%mod;
    }
    return res;
}
int main() {
    scanf("%d%d",&n,&m);
    init();
    printf("%d\n",solve(n,m));
}
 
[SDOI2015] 约数个数和
题目描述
设  
     
      
       
       
         d 
        
       
         ( 
        
       
         x 
        
       
         ) 
        
       
      
        d(x) 
       
      
    d(x) 为  
     
      
       
       
         x 
        
       
      
        x 
       
      
    x 的约数个数,给定  
     
      
       
       
         n 
        
       
         , 
        
       
         m 
        
       
      
        n,m 
       
      
    n,m,求
  
      
       
        
         
         
           ∑ 
          
          
          
            i 
           
          
            = 
           
          
            1 
           
          
         
           n 
          
         
         
         
           ∑ 
          
          
          
            j 
           
          
            = 
           
          
            1 
           
          
         
           m 
          
         
        
          d 
         
        
          ( 
         
        
          i 
         
        
          j 
         
        
          ) 
         
        
       
         \sum_{i=1}^n\sum_{j=1}^md(ij) 
        
       
     i=1∑nj=1∑md(ij)
输入格式
输入文件包含多组测试数据。
 第一行,一个整数  
     
      
       
       
         T 
        
       
      
        T 
       
      
    T,表示测试数据的组数。
 接下来的  
     
      
       
       
         T 
        
       
      
        T 
       
      
    T 行,每行两个整数  
     
      
       
       
         n 
        
       
         , 
        
       
         m 
        
       
      
        n,m 
       
      
    n,m。
输出格式
T T T 行,每行一个整数,表示你所求的答案。
样例 #1
样例输入 #1
2
7 4
5 6
 
样例输出 #1
110
121
 
提示
【数据范围】
 对于  
     
      
       
       
         100 
        
       
         % 
        
       
      
        100\% 
       
      
    100% 的数据, 
     
      
       
       
         1 
        
       
         ≤ 
        
       
         T 
        
       
         , 
        
       
         n 
        
       
         , 
        
       
         m 
        
       
         ≤ 
        
       
         50000 
        
       
      
        1\le T,n,m \le 50000 
       
      
    1≤T,n,m≤50000。
思路

 
 
AC代码
#include <bits/stdc++.h>
using namespace std;
const long long N=5e4+5;
long long tot,mu[N],p[N];
long long s[N];
bool flg[N];
void init() {
    mu[1]=1;
    for(long long i=2;i<=5e4;++i) {
        if(!flg[i]) p[++tot]=i,mu[i]=-1;
        for(long long j=1;j<=tot&&i*p[j]<=5e4;++j) {
            flg[i*p[j]]=1;
            if(i%p[j]==0) {
                mu[i*p[j]]=0;
                break;
            } else {
                mu[i*p[j]]=-mu[i];
            }
        }
    }
    for(long long i=1;i<=5e4;++i) mu[i]+=mu[i-1];
    for(long long x=1;x<=5e4;++x) {
        long long res=0;
        for(long long i=1,j;i<=x;i=j+1) j=x/(x/i),res+=(j-i+1)*(x/i);
        s[x]=res;
    }
    return ;
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	init();
	long long T;
	cin>>T;
	while(T--){
		long long n,m;
		cin>>n>>m;
		if(n>m)swap(n,m);
		long long ans=0;
		for(long long i=1,j;i<=n;i=j+1){
			j=min(n/(n/i),m/(m/i));
			ans+=(mu[j]-mu[i-1])*s[n/i]*s[m/i];
		}
		cout<<ans<<endl;
	}
}
 
[SDOI2008] 仪仗队
题目描述
作为体育委员,C 君负责这次运动会仪仗队的训练。仪仗队是由学生组成的 N × N N \times N N×N 的方阵,为了保证队伍在行进中整齐划一,C 君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是否整齐(如下图)。

现在,C 君希望你告诉他队伍整齐时能看到的学生人数。
输入格式
一行,一个正整数 N N N。
输出格式
输出一行一个数,即 C 君应看到的学生人数。
样例 #1
样例输入 #1
4
 
样例输出 #1
9
 
提示
对于 100 % 100 \% 100% 的数据, 1 ≤ N ≤ 40000 1 \le N \le 40000 1≤N≤40000。
思路

 
AC代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long ll;
  
const int maxn=50000;
  
int vis[maxn];
int prime[maxn];
int phi[maxn];
int sum[maxn];
  
int main()
{
    phi[1]=1;
    sum[1]=1;
    int k=-1;
    for(int i=2;i<=40000;i++)
    {
        if(!vis[i])
        {
            prime[++k]=i;
            phi[i]=i-1;
        }
        for(int j=0;j<=k&&i*prime[j]<=40000;j++)
        {
            vis[i*prime[j]]=1;
            if(i%prime[j]==0)
            {
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
            phi[i*prime[j]]=phi[i]*phi[prime[j]];
        }
        sum[i]=sum[i-1]+phi[i];
    }
    int n;
    scanf("%d",&n);
    if(n==1)
        printf("0\n");
    else
        printf("%d\n",2*sum[n-1]+1);
    return 0;
}
 
Product
题目背景
C Y J i a n {\rm CYJian} CYJian:“听说 g c d gcd gcd和 ∑ \sum ∑套起来比较好玩??那我就…”
题目描述
C Y J i a n {\rm CYJian} CYJian最近闲的玩起了 g c d gcd gcd。。他想到了一个非常简单而有意思的式子:
∏ i = 1 N ∏ j = 1 N l c m ( i , j ) g c d ( i , j ) ( m o d 104857601 ) \prod_{i=1}^N\prod_{j=1}^N\frac{lcm(i,j)}{gcd(i,j)}\ (\bmod\ 104857601) i=1∏Nj=1∏Ngcd(i,j)lcm(i,j) (mod 104857601)
C Y J i a n {\rm CYJian} CYJian已经算出来这个式子的值了。现在请你帮他验算一下吧。 C Y J i a n {\rm CYJian} CYJian只给你 0.2 s 0.2s 0.2s的时间哦。
2024.5.11 upd: 放宽时空限制。
输入格式
一行一个正整数 N N N。
输出格式
一行一个正整数,表示答案模 104857601 104857601 104857601的值。
样例 #1
样例输入 #1
5
 
样例输出 #1
585494
 
提示
样例解释:
| l c m g c d \frac{lcm}{gcd} gcdlcm | 1 | 2 | 3 | 4 | 5 | 
|---|---|---|---|---|---|
| 1 | 1 | 2 | 3 | 4 | 5 | 
| 2 | 2 | 1 | 6 | 2 | 10 | 
| 3 | 3 | 6 | 1 | 12 | 15 | 
| 4 | 4 | 2 | 12 | 1 | 20 | 
| 5 | 5 | 10 | 15 | 20 | 1 | 
对于 30 % 30\% 30%的数据: 1 ≤ N ≤ 5000 1 \leq N \leq 5000 1≤N≤5000
对于 100 % 100\% 100%的数据: 1 ≤ N ≤ 1000000 1 \leq N \leq 1000000 1≤N≤1000000
思路

 
 
 
 
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=1000005,mod=104857601;
ll n,cnt,ans1=1,prim[N],ans2=1,pai[N];
bool vis[N];
inline ll power( ll a,ll b){
	 ll r=1;
    while(b)
    {
        if(b&1ll) r=1ll*r*a%mod;
        b>>=1ll;
        a=1ll*a*a%mod;
    }
    return r;
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n;
    pai[1]=1;
    for(ll i=2;i<=n;++i)
    {
    	ans1=ans1*i%mod;
        if(!vis[i]) prim[++cnt]=i,pai[i]=i-1;
        for(ll j=1;j<=cnt;++j)
        {
            if(prim[j]*i>n) break;
            vis[prim[j]*i]=1;
            if(i%prim[j]==0) {pai[i*prim[j]]=pai[i]*prim[j];break;}
            pai[i*prim[j]]=pai[prim[j]]*pai[i];
        }
    }
    for(ll i=1;i<=n;++i) pai[i]=pai[i]*2+pai[i-1]%(mod-1);
    ans1=power(ans1,2*n);
    for(ll i=2;i<=n;++i) ans2=ans2*power(i,pai[n/i]-1)%mod;
    cout<<(ans1*power(1ll*ans2*ans2%mod,mod-2))%mod<<endl;
    return 0;
}
 
这是我的第十五篇文章,如有纰漏也请各位大佬指正
辛苦创作不易,还望看官点赞收藏打赏,后续还会更新新的内容。



















