2023CSP-J组真题 3. upe 一元二次方程

本文介绍了如何使用C++编程语言解决线上OJ中的一道关于一元二次方程实数解的问题,涉及约分操作、分类讨论以及特殊情况下输出格式的处理。核心是通过约分函数处理分子分母,确保分母非负并输出较大解。
摘要由CSDN通过智能技术生成

线上OJ:信息学奥赛一本通(C++版)在线评测系统

 对于学过一元二次方程的同学来说,这道题理解起来不会太难。只需要按照题意模拟即可。

1、当\Delta < 0 时,方程无实数解,直接输出 "NO"

2、当\Delta = 0 时,方程有且只有一个实数解,为\frac{-b}{2a},需先约分,再输出结果

     2.1 约分方法:先求出分子和分母的最大公约数d(d = gcd(\left | b \right |, \left | 2a \right |)),然后分子分母同除d(\frac{(-b)\div d}{2a\div d})即可。

     2.2 输出前要检查分母不能为负。如果分母为负,则需调整分子分母的符号,再输出。

3、当\Delta > 0 时,需要分类讨论

     3.1  如果\sqrt{\Delta }= r 时(r 为整数),则方程的较大解为

     \left\{\begin{matrix} \frac{-b+r}{2a},a>0\\ \frac{-b-r}{2a},a<0 \end{matrix}\right.

     3.2 如果\sqrt{\Delta }= r\sqrt{t} 时(r,t 均为整数,t不为完全平方数),则方程的较大解为

     \left\{\begin{matrix} \frac{-b}{2a}+\frac{r\sqrt{t}}{2a},a>0\\ \frac{-b}{2a}-\frac{r\sqrt{t}}{2a},a<0 \end{matrix}\right.

注1:题中要求 "如果方程有实数解,则按要求的格式输出两个实数解中的较大者",故只需要输出较大值一个。

注2:输出之前同样需要检查分母不能为负。如果分母为负,则需调整分子分母的符号,再输出。

4、关于r的求法

      从\sqrt{\Delta }的向下取整的整数开始,暴力枚举第一个使 (delta % (r*r)) == 0 的数即可

      举例:delta=150,\sqrt{150} = 12.2474,向下取整是12。从12向下递减,5是第一个满足 150%25==0,所以r=5 。且 t= delta/(r*r)=6,即\sqrt{150}=5\sqrt{6}

核心要点

  1. 约分的函数单独写,通过地址和指针来传递。约分就是分子分母同除最大公约数。
  2. 由于输出格式要求,分母不能为负值。如果分母为负,要分子分母都变号。

题解代码: 

#include<bits/stdc++.h>
#define ll long long
using namespace std;

ll gcd(ll a, ll b) {return b ? gcd(b, a%b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b)*b;}

ll T, M, a, b, c, delta;

// 化简p/q,即约分。约分的原理是:分子分母同除以最大公约数 
void yuefen(ll *p, ll *q)
{
	ll pq = gcd(abs(*q), abs(*p));	// 求出 p和 q的最大公约数 
	*p /= pq, *q /= pq;				// 分子分母同除最大公约数,即化简 p/q 
	if(*q < 0) *q = -*q, *p = -*p;	// 保证分母>0 
	
	return;
} 

int main()
{
	cin >> T >> M; 
	while(T--)
	{
		cin >> a >> b >> c;
		delta = b*b - 4*a*c;
		if(delta < 0)
		{
			cout << "NO" << endl;
		}
		else if(delta == 0)		//  只有一个解,x = -b/2a 
		{
			ll p = -b, q = 2*a;
			yuefen(&p, &q);
			if(q == 1) cout << p << endl; // 如果约分后分母为 1,则分子即为解,直接输出即可 
			else cout << p << "/" << q << endl; //printf("%lld/%lld\n",p,q);	// 否则输出 p/q 
		}
		else 	// 有两个解,但更号正好开尽(比如 3=sqrt(9))。按题目要求,输出最大解即可
		{
			ll p = -b, q = 2*a;
			ll sq = (ll)sqrt(delta); 	// 对 delta开更号,并保留整数部分 
			if(sq * sq == delta)			// 如果 sq 正好是平方根 ,则解为 (p + sq)/q 和  (p - sq)/q
			{
				if(q > 0) p += sq;		// 因为只输出最大的解,所以当分母>0时,分子 +sq 为较大值 
				else p -= sq;			// 所以当分母<0时,分子 -sq 为较大值 
				yuefen(&p, &q);
				if(q == 1) cout << p << endl; 	// 如果约分后分母为 1,则分子即为解,直接输出即可
				else cout << p << "/" << q << endl; //printf("%lld/%lld\n",p,q);	// 否则输出 p/q
			}
			else	// 更号开不尽,则要注意输出格式,举例 3/2+sqrt(5)/2
			{
				yuefen(&p, &q);			// 先处理 -b/2a+ 
				if(p != 0)						// 先输出 -b/2a+
				{
					if(q == 1) cout << p << "+"; // 如果约分后分母为 1,则分子即为解,直接输出即可
					else cout << p << "/" << q << "+"; // 否则输出 p/q+
				}
				// 再处理 + 后面的内容 
				q = abs(2*a);		// 由于输出大值,为了简化处理,+后面的分子分母都当成是正的即可 
				ll t = 0;
				for(int r = sq; r >= 1; r--)	// 从sq开始向下穷举 
				{
					if( (delta % (r*r)) == 0)	// 举例:delta=150,sq=12。从12向下递减,5是第一个满足 150%25==0,所以r=5 
					{
						p = r;					// sqrt(150) = 5 * sqrt(6)   即 r=5, t=6 
						t = delta/(r*r);
						break;
					}
				}					
				yuefen(&p, &q);
				if(p == q) cout << "sqrt(" << t << ")" << endl; //printf("sqrt(%lld)\n",t);	// 如果分子分母相等,则只输出 sqrt(t)即可 
				else if(q == 1) cout << p << "*sqrt(" << t << ")" << endl; // printf("%lld*sqrt(%lld)\n",p,t);
				else if(p == 1) cout << "sqrt(" << t << ")/" << q << endl; // printf("sqrt(%lld)/%lld\n",t,q);
				else cout << p << "*sqrt(" << t << ")/" << q << endl; // printf("%lld*sqrt(%lld)/%lld\n",p,t,q);
			}
		}
	}
	return 0;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值