题解 P8319 『JROI-4』分数
受上场月赛的 B 启发,设 x x x 的最小因数为 y y y,则血书女装过程为:
0 x → 1 x → . . . → y x , 1 x / y → 2 x / y → . . . \displaystyle\frac 0x\to \frac1x\to...\to\frac yx,\frac1{x/y}\to\frac2{x/y}\to... x0→x1→...→xy,x/y1→x/y2→...
然后 1 x / y \frac1{x/y} x/y1 后面的步骤数就是 f ( x / y ) − 1 f(x/y)-1 f(x/y)−1 了。所以我们可以从 f ( x / y ) f(x/y) f(x/y) 推出 f ( x ) f(x) f(x):
f ( x ) = { 1 i f x = 1 x i f x ∈ P y + f ( x / y ) − 1 i f x ∉ P & x ≠ 1 f(x) = \begin{cases} 1&if~x=1\\ x&if~x\in\Bbb{P}\\ y+f(x/y)-1&if~x\not\in\Bbb{P}~\&~x\not= 1 \end{cases} f(x)=⎩⎪⎨⎪⎧1xy+f(x/y)−1if x=1if x∈Pif x∈P & x=1
判断质数以及对每个 x x x 求最小质因子 y y y 可以用线性筛解决。
//LGR-108 B
#include <bits/stdc++.h>
using namespace std;
const int N = 2e6 + 10;
int v[N], prime[N], mindiv[N], ans[N], mx[N];
inline void getf(int n){
int cnt = 0;
for(int i = 2; i <= n; ++ i){
if(!v[i]) prime[++cnt] = i, mindiv[i] = i;
for(int j = 1; j <= cnt && i * prime[j] <= n; ++ j){
v[i*prime[j]] = 1;
mindiv[i*prime[j]] = prime[j];
if(i%prime[j] == 0) break;
}
}
}
int main(){
int t, n; scanf("%d", &t);
getf(N-10);
ans[1] = 1; mx[1] = 1;
for(int i = 2; i <= N-10; ++ i){
if(!v[i]) ans[i] = i;
else ans[i] = mindiv[i] + ans[i/mindiv[i]] - 1;
mx[i] = max(mx[i-1], ans[i]);
}
while(t--){
scanf("%d", &n);
printf("%d\n", mx[n]);
}
return 0;
}
当然,可以很容易发现一个性质:
max 1 ≤ i ≤ x { f ( x ) } = max 1 ≤ p ≤ x , p ∈ P { p } \max_{1\leq i \leq x}\{f(x)\}=\max_{1\leq p \leq x,p\in\Bbb{P}}\{p\} 1≤i≤xmax{f(x)}=1≤p≤x,p∈Pmax{p}
即 f ( x ) f(x) f(x) 为 [ 1 , x ] [1,x] [1,x] 中最大的质数。理解也很容易:质数不会被约分,所以他只能不停地分子 + 1 +1 +1,因此比合数答案大。
记得特判以下 f ( 1 ) f(1) f(1)。
//LGR-108 B
#include <bits/stdc++.h>
using namespace std;
const int N = 2e6 + 10;
int v[N], prime[N], mx[N];
inline void getf(int n){
int cnt = 0;
for(int i = 2; i <= n; ++ i){
if(!v[i]) prime[++cnt] = i;
for(int j = 1; j <= cnt && i * prime[j] <= n; ++ j){
v[i*prime[j]] = 1;
if(i%prime[j] == 0) break;
}
}
}
int main(){
int t, n; scanf("%d", &t);
getf(N-10);
mx[1] = 1;
for(int i = 2; i <= N-10; ++ i){
if(!v[i]) mx[i] = i;
else mx[i] = mx[i-1];
}
while(t--){
scanf("%d", &n);
printf("%d\n", mx[n]);
}
return 0;
}