『JROI-4』分数

题面

image

image

点评

这是一道数论题。

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分

注:这是一个大的突破。

  1. 如果 \(n\) 是质数或 \(n=1\),那么 \(f(n)=n\)

很好理解,因为没有了约分。

  1. 如果 \(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;
}

码风可能有点丑,敬请理解。

posted @ 2022-05-01 15:52  蒟蒻xiezheyuan  阅读(39)  评论(0编辑  收藏  举报