『JROI-4』分数
题面
点评
这是一道数论题。
40分
按照题意递推即可。时间复杂度 \(O(\sum n)\)。
简要代码如下:
int nans=0;
void dfs(int fz,int fm,int ndeep){
if(fz==fm){
nans=max(nans,ndeep);
}
else{
fz++;
int tgcd = Gcd(fz,fm);
if(tgcd!=1){
fz/=tgcd;
fm/=tgcd;
}
dfs(fz,fm,ndeep+1);
}
}
70分
注:这是一个大的突破。
- 如果 \(n\) 是质数或 \(n=1\),那么 \(f(n)=n\)。
很好理解,因为没有了约分。
- 如果 \(n\) 是 合数,那么 \(f(n) \lt n\)。
也很好理解,因为一旦有了约分,步骤就会被缩短。
所以我们可以从 \(n\) 开始从大到小暴力枚举质数。
时间复杂度不大好算(蒟蒻不会素数定理),但是比暴力好太多了。
简要代码如下:
int ans=0;
for(int i=n;i>=1;i--){
if(isprime(i)){
ans=i;
break;
}
}
100分
每一次都寻找太浪费了。我们可以用一个线性筛筛出所有的质数,然后再质数表上二分。
同样,对于 \(n\) 是质数,可以直接 \(O(1)\) 得到 \(f(n)=n\)。
最差时间复杂度 \(O(\max\{n\}+\sum{\log n})\)。可以承受。
代码如下:
#include <bits/stdc++.h>
#define gcd __gcd
using namespace std;
int t;
struct LinearPrime{
const static int SIZE = 1e8+5;
bool isPrime[SIZE];
int Prime[SIZE];
int cnt=0;
void run(int n){
memset(isPrime,1,sizeof(isPrime));
isPrime[1]=false;
for(int i=2;i<=n;i++){
if(isPrime[i]){
Prime[++cnt]=i;
}
for(int j=1;j<=cnt&&i*Prime[j]<=n;j++){
isPrime[i*Prime[j]]=0;
if(i%Prime[j]==0){
break;
}
}
}
}
} Pri;
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
cin>>t;
Pri.run(2e6+5);
while(t--){
int n;
cin>>n;
if(n==1){
cout<<1<<endl;
continue;
}
if(Pri.isPrime[n]){
cout<<n<<endl;
continue;
}
int pos=upper_bound(Pri.Prime+1,Pri.Prime+Pri.cnt,n)-Pri.Prime;
cout<<Pri.Prime[pos-1]<<endl;
}
return 0;
}
码风可能有点丑,敬请理解。