codevs 2190 有理逼近 题解


题目描述 Description

对于一个素数P,我们可以用一系列有理分数(分子、分母都是不大于N的自然数)来逼近sqrt(p),例如P=2,N=5的时候:1/1<5/4<4/3 任 务 :
给定P、N(N>sqrt(p)),求X、Y、U、V,使x/y

输入描述 Input Description

输入文件的第一行为P、N

输出描述 Output Description

输出文件只有一行,格式为“X/Y U/V”。注意,答案必须是既约的,也就是说分子、分母的最大公约数必须等于1。

样例输入 Sample Input

样例1:
2 5
样例2:
5 100

样例输出 Sample Output

样例1:
4/3 3/2

样例2:
38/17 85/38

数据范围及提示 Data Size & Hint

 P、N<30000

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

说实话,这道题真的把我唬住了……

刚看到这道题,感觉明显的二分,可是如何分?怎么分?是一个问题。

于是我想我没可以枚举分子和分母,然后找最接近的,然而 P、N<30000这的把我唬住了…

…尽管我看见了gcd(分子,分母)=1这个提示,但是我还是没有去写它(事实证明,这题很水,暴力可以a)

在时间竟破的情况下,我选择了放弃……

中午评测完以后,我发现,我们可以枚举固定区间内的分子,因为分母是从2-n的,那些远大于 分母*(p)^(1/2)的分子

是没有必要去枚举的。所以我们可以取(p)^(1/2)的上界和下界(即上下取整)这样我们可以把每一个分母的分子限制

在一个很小的区间内,再加上gcd(分子,分母)=1,还有二分枚举答案,这题就可以过了。

由于本人不会写二分,所以,我开了一个大根堆,一个小根堆来维护。看来,今晚还要补习一下二分了!!

注意:有可能输出如1/1或者2/1的情况!!

+++++++++++++++++++++代码如下++++++++++++++++++++++++++++++++++++

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
struct node1{
	int son,mot;double w;
	bool operator < (const node1 &a) const 
    {  
       return wa.w;//×îСֵÓÅÏÈ   
    }  
}b[3001000];
priority_queueq1;
priority_queueq2;

int gcd(int x,int y)
{
	return y?gcd(y,x%y):x;
}

int main()
{
	cin>>q>>n;p=sqrt(q);
	int l=floor(sqrt(q)),r=ceil(sqrt(q));
	for(int k=1,kk=1,i=2;i<=n;i++)
	  for(int j=i*l;j<=min(n,i*r);j++)
	  if(gcd(i,j)==1)
	  {
	  	double jj,ii,z;
	  	jj=(double)j;
	  	ii=(double)i;
	  	z=jj/ii;//cout<<<p)
		{
			b[kk].son=j;
			b[kk].mot=i;
			b[kk].w=z;
			q2.push(b[kk]);kk++;
		}
		
	  }
	if(!q1.empty())
	cout<



题目描述 Description

对于一个素数P,我们可以用一系列有理分数(分子、分母都是不大于N的自然数)来逼近sqrt(p),例如P=2,N=5的时候:1/1<5/4<4/3 任 务 :
给定P、N(N>sqrt(p)),求X、Y、U、V,使x/y

输入描述 Input Description

输入文件的第一行为P、N

输出描述 Output Description

输出文件只有一行,格式为“X/Y U/V”。注意,答案必须是既约的,也就是说分子、分母的最大公约数必须等于1。

样例输入 Sample Input

样例1:
2 5
样例2:
5 100

样例输出 Sample Output

样例1:
4/3 3/2

样例2:
38/17 85/38

数据范围及提示 Data Size & Hint

 P、N<30000

你可能感兴趣的:(noip模拟赛,CODEVS)