最 大 公 约 数 最大公约数 最大公约数
正 解 部 分 \color{red}{正解部分} 正解部分
最优情况中, g c d gcd gcd 每次变化都是 质因数分解中的一个质因子次数减少 1 1 1, 所以 f m a x ( n ) f_{max}(n) fmax(n) 为 [ 1 , n ] [1, n] [1,n] 中 质因数分解质数次幂的和 的 最大值 加上 1 1 1.
首先
f
m
a
x
(
n
)
f_{max}(n)
fmax(n) 分解质因数后一定是
2
x
3
y
2^x3^y
2x3y 的形式, 其中
x
∈
N
,
y
∈
{
0
,
1
}
x \in \N, y \in \{0, 1\}
x∈N,y∈{0,1}
假设存在
t
>
3
t > 3
t>3, 使得
f
m
a
x
(
n
)
f_{max}(n)
fmax(n) 分解质因数后为
t
2
x
3
y
t2^x3^y
t2x3y, 则
t
t
t 可以替换为
2
?
2^?
2?,答案不会更差, 因此
f
m
a
x
(
n
)
=
⌊
log
2
n
⌋
+
1
f_{max}(n) = \lfloor \log_2n \rfloor + 1
fmax(n)=⌊log2n⌋+1 .
接下来计算
f
(
p
)
=
f
m
a
x
(
n
)
f(p) = f_{max}(n)
f(p)=fmax(n) 的
p
p
p 的个数, 考虑 从左往右 填数, 前面的数字一定是
2
x
3
y
2^x3^y
2x3y 的形式,
设
F
[
i
,
x
,
y
]
F[i, x, y]
F[i,x,y] 表示 填了前
i
i
i 个数字, 前
i
i
i 个数字的
g
c
d
gcd
gcd 为
2
x
3
y
2^x3^y
2x3y 的方案数,
初值
- F [ 1 , ⌊ log 2 N ⌋ , 0 ] = 1 F[1, \lfloor \log_2 N \rfloor, 0] = 1 F[1,⌊log2N⌋,0]=1
- F [ 1 , ⌊ log 2 N ⌋ − 1 , 1 ] = 1 ( 2 ⌊ log 2 N ⌋ − 1 × 3 ≤ N ) F[1, \lfloor \log_2 N \rfloor - 1, 1] = 1\ \ \ \ \ \ \ \ \ \ \ \ \ \ (2^{\lfloor \log_2 N \rfloor - 1}\times3 \le N) F[1,⌊log2N⌋−1,1]=1 (2⌊log2N⌋−1×3≤N)
转移 时使得 x x x 或 y y y 至多其中一个减一,
-
x , y x, y x,y 不变: F [ i , x , y ] + = F [ i − 1 , x , y ] × ( ⌊ N 2 x 3 y ⌋ − ( i − 1 ) ) F[i, x, y] \ += F[i-1, x, y] \times \left( \lfloor \frac{N}{2^x3^y} \rfloor -(i-1) \frac{}{}\right) F[i,x,y] +=F[i−1,x,y]×(⌊2x3yN⌋−(i−1))
-
x x x 减 1 1 1: F [ i , x , y ] + = F [ i − 1 , x + 1 , y ] × ( ⌊ N 2 x 3 y ⌋ − ⌊ N 2 x + 1 3 y ⌋ ) \ \ \ \ F[i, x, y]\ + = F[i-1, x+1,y] \times \left( \lfloor \frac{N}{2^x3^y} \rfloor - \lfloor \frac{N}{2^{x+1}3^y}\rfloor \right) F[i,x,y] +=F[i−1,x+1,y]×(⌊2x3yN⌋−⌊2x+13yN⌋)
-
y y y 减 1 1 1: F [ i , x , y ] + = F [ i − 1 , x , y + 1 ] × ( ⌊ N 2 x 3 y ⌋ − ⌊ N 2 x 3 y + 1 ⌋ ) \ \ \ \ F[i, x, y]\ + = F[i-1, x, y+1]\times\left( \lfloor \frac{N}{2^x3^y} \rfloor - \lfloor \frac{N}{2^x3^{y+1}}\rfloor \right) F[i,x,y] +=F[i−1,x,y+1]×(⌊2x3yN⌋−⌊2x3y+1N⌋)
最后答案即为 F [ N , 0 , 0 ] F[N, 0, 0] F[N,0,0] .
实 现 部 分 \color{red}{实现部分} 实现部分
#include<bits/stdc++.h>
#define reg register
const int mod = 1e9 + 7;
const int maxn = 1e6 + 5;
int N;
int F[maxn][22][2];
int Ksm(int a, int b){ int s=1; while(b){ if(b&1)s=1ll*s*a%mod; a=1ll*a*a%mod;b>>=1; } return s; }
int main(){
scanf("%d", &N); int t = log2(N);
F[1][t][0] = 1; if(Ksm(2, t-1)*3 <= N) F[1][t-1][1] = 1;
for(reg int i = 2; i <= N; i ++)
for(reg int x = 0; x <= t; x ++)
for(reg int y = 0; y <= 1; y ++){
int &cur = F[i][x][y], t1 = Ksm(2,x)*Ksm(3,y), t2 = Ksm(2,x+1)*Ksm(3,y), t3 = Ksm(2,x)*Ksm(3,y+1);
if(N/t1 > i-1) cur = (cur + 1ll*F[i-1][x][y]*(N/t1-i+1)%mod) % mod;
if(x != t) cur = (cur + 1ll*F[i-1][x+1][y]*(N/t1 - N/t2)%mod) % mod;
if(y != 1) cur = (cur + 1ll*F[i-1][x][y+1]*(N/t1 - N/t3)%mod) % mod;
}
printf("%d\n", F[N][0][0]);
return 0;
}