P9750 [CSP-J 2023] 一元二次方程

P9750 [CSP-J 2023] 一元二次方程

你说的对,但是我期中考前来写题解。

从头开始想这个题,比较抽象的模拟题。

首先几个注意的事项以及一些细节:

  • 下文提到的化简,指的是对于分子分母同时除以他们的最大公因数。同时注意如果分母是 11,直接输出分子即可。

  • 下文提到的对分母的正负性讨论,指的是如果分母可能是正数或者负数,那么讨论分子可能出现的情况。假设如果分母是负数,枚举分子可能出现的两负,两正,一正一负,发现如果要取最大值的话,要求分子尽可能的小,那就是说明 b±Δ-b\pm\sqrt{\Delta} 要取负号,分母是正的同理。可以发现,这个取法和 Δ\sqrt{\Delta} 的值无关。

首先对于 Δ<0\Delta<0,显然无解。

如果 Δ=0\Delta=0,那我们只用输出 b2a\frac{-b}{2a} 即可。这两个都是整数,直接化简。

如果 Δ>0\Delta >0,那么我们考虑先把 Δ\Delta 算出来,因为它最多也是到 10610^6,所以一种方法是直接枚举他的最大的平方因子,但是这个人脑抽用了预处理质数然后看每个质数的偶数次平方还获得最大平方因子的方法。仅供参考。

为了方便,我们把 b-bΔ\Delta 分开考虑。这时候再考虑,如果 Δ\Delta 恰好是一个完全平方数,那么它势必可以和前面的 b-b 合并起来,在这里对分母的正负性讨论,同时化简,否则如果不是完全平方数,那就分开化简以后再进行对分母的正负性讨论。

同时注意 b=0b=0 的情况,因为分开来看了,这时候不能输出前置的 00

代码写得比较抽象。

#include<bits/stdc++.h>
using namespace std;
const int N =4e4+10;
int Prime[N],num;
bool vis[N];
int GCD(int a,int b){
	if(b==0)	return a;
	return GCD(b,a%b);
}
int Quickpow(int a,int b){
	int ans=a,now=1;
	while(b>0){
		if(b&1)	now*=ans;
		ans*=ans;
		b>>=1;
	}
	return now;
} 
void init(){
	for(int i=2;i<=32000;i++){
		if(vis[i]==false)	Prime[++num]=i;
		for(int j=1;j<=num&&i*Prime[j]<=32000;j++){
			vis[i*Prime[j]]=true;
			if(i%Prime[j]==0)
				break;
		}
	}
}
int main(){
//	freopen("uqe.in","r",stdin);
//	freopen("uqe.out","w",stdout);
	init();
	int t,M;
	cin>>t>>M;
	while(t--){
		int a,b,c;
		cin>>a>>b>>c;
		int now=b*b-4*a*c; 
		if(b*b-4*a*c<0)	{cout<<"NO"<<endl;continue;}
		if(b*b-4*a*c==0&&b==0)	{cout<<"0"<<endl;continue;}
		if(now==0){
			int G=GCD(b,2*a);
			b/=G,a=a*2/G;
			if(a==1)	cout<<-b<<endl;
			else if((a<0&&b<0)||(a>0&&b>0))	cout<<"-"<<abs(b)<<"/"<<abs(a)<<endl;
			else{
				if(a<0)	cout<<b<<"/"<<abs(a)<<endl;
				else	cout<<abs(b)<<"/"<<a<<endl;
			}
		}
		else{
//			cout<<now<<endl;
			int lst=a;
			int predis=1;
			for(int i=1;i<=num;i++){
//				if(now%(Prime[i]*Prime[i])==0)	predis*=Prime[i],now/=Prime
				int lsst=1,Q=0;
				while(now%(lsst*Prime[i])==0)	lsst*=Prime[i],Q++;
				if(Q%2!=0)	Q--;
				predis*=Quickpow(Prime[i],Q/2),now/=Quickpow(Prime[i],Q); 
				if(now<Prime[i])	break;
			}
			if(now==1){
				a=a*2;
				int pre1=-b+predis,pre2=-b-predis,ch;
//				cout<<pre1<<" "<<pre2<<endl;
				if(a<0){
					if(pre1>=0&&pre2<0)	ch=pre2;
					else if(pre1<0&&pre2>=0)	ch=pre1;
					else if(pre1>=0&&pre2>=0)	ch=min(pre1,pre2);
					else	ch=min(pre1,pre2);
				}
				else{
					if(pre1>0&&pre2<=0)	ch=pre1;
					else if(pre1<=0&&pre2>0)	ch=pre2;
					else if(pre1>=0&&pre2>=0)	ch=max(pre1,pre2);
					else	ch=max(pre1,pre2);
				}				
//				cout<<ch<<" "<<a<<endl;
				int g=GCD(ch,a);
				if(ch==0)	{cout<<0<<endl;continue;}
				ch/=g,a/=g; 
				if(a==1)	cout<<ch<<endl;
				else if((a<0&&ch<0)||(a>0&&ch>0))	cout<<abs(ch)<<"/"<<abs(a)<<endl;
				else{
					if(a<0)	cout<<"-"<<ch<<"/"<<abs(a)<<endl;
					else	cout<<"-"<<abs(ch)<<"/"<<a<<endl;
				}
				continue;
			}
			if(b!=0){	
				int G=GCD(b,2*a);
				b=b/G,a=a*2/G;
				if(a==1)	cout<<-b<<"+";
				else if((a<0&&b<0)||(a>0&&b>0))	cout<<"-"<<abs(b)<<"/"<<abs(a)<<"+";
				else{
					if(a<0)	cout<<b<<"/"<<abs(a)<<"+";
					else	cout<<abs(b)<<"/"<<a<<"+";
				}
			}
			a=lst;
			int G=GCD(a*2,predis);
			predis/=G,a=a*2/G;
			a=abs(a),predis=abs(predis);
			if(predis==1){
				if(a==1)	cout<<"sqrt("<<now<<")"<<endl;
				else cout<<"sqrt("<<now<<")"<<"/",cout<<abs(a)<<endl;
			}
			else{
				if(a==1)	cout<<abs(predis)<<"*"<<"sqrt("<<now<<")"<<endl;
				else{
					cout<<predis;
					cout<<"*"<<"sqrt("<<now<<")"<<"/";
					cout<<a<<endl;
				}
			}
		}
	}	
}
/*
9 1000
1 0 -432
1 -3 1
2 -4 1
1 7 1

*/
posted @   June_Failure  阅读(116)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示