【基础】模拟题 多项式处理类

自用 

 因式分解

P2378 因式分解II - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目描述

小玉上了初中,开始学因式分解。可是她怎么都解不出来。所以她求你帮忙。

她给你看了她的作业,就是因式分解。由于刚开始学,就降低了难度。

我们假设作业里面的代数只有一个x。最高指数是2,且最高指数的系数是1。当x前的系数是1时,1省去……(反正作业题目符合我们的日常写法)

我们帮她解决下这个“简单”的问题吧!虽然听起来挺容易,但是编程需要考虑很多情况呢!

保证作业答案的数字都是整数。

// 这跟神器有什么关系么?神说,帮助他人,积累善行,神器自然出现。哈哈哈哈好牵强的解释~

//为了帮助在5月月赛ac这道题目,kkksc03偷偷地进行以下的温馨提示:

//数据可能会比较刁钻,请考虑到各种情况,包括只有输入一项的情况、中间过程会不会超maxlongint的情况等。

//lzn:喂!你这是透题行为,是要上法庭的!

//absi2011:样例输出里的"//"及以后字符只是注解,并不要你输出

/* absi2011:输入规范好不和谐啊...

我只是来补充一下...

如果x或者常数项的系数是0 整个省略掉

哦,x的系数是-1的话 也会把1省去...

保证输入的那玩意儿可以分解....而且分解出来都是整数...

*/

// 原作: 2022.7.24 没想到初中时候贡的题已经坑害了这么多人ac了. 现在已经大二,时过境迁,已经完全不会了哈哈哈

输入格式

一个多项式,要求前面已述。各个系数<=maxlongint。

输出格式

几个乘积。答案也符合日常写法。为了方便老师批改,若将答案表示成(x+a)(x+b),则a>b。

什么是日常写法?

1、(x+0)写成x

2、(x+a)(x+a)写成(x+a)^2

3、有时候可以这样写:(x-3)。但是不能出现类似于(x+-3)这样的写法

输入输出样例

输入 #1复制

x^2-4

输出 #1复制

(x+2)(x-2)
//而不能写成(x-2)(x+2)或者(x+2)(x+-2)

输入 #2复制

x^2+5x+4

输出 #2复制

(x+4)(x+1)
//不能写成(x+1)(x+4)

输入 #3复制

x^2-2x+1

输出 #3复制

(x-1)^2

输入 #4复制

x^2+x

输出 #4复制

(x+1)x
//反过来是不可以的。

说明/提示

x次数不高于2次,项数不高于3项,降幂排列。

这题比较简单(虽然调试了这么久),先读入多项式ax2+bx+cax2+bx+c,再求出a,b,ca,b,c的值,再套求根公式 x=−b±b2−4ac2ax=2a−b±b2−4ac​​,即可因式分解。代码如下

吐槽一下。代码有必要那么长吗?

我的代码巨短

#include <bits/stdc++.h>
using namespace std;
string a, c;
double b[10], x1, x2;
void work(double x) {
	if (x == 0) cout << "x";
	else {
		cout << "(x";
		if (x > 0) cout << "+" << x << ")";
		else cout << "-" << -x << ")";
	}
}
int main() {
	cin >> a;
	b[1] = 1;//x^2的系数为1 
	a.erase(0, 3);
	int pos = a.find('x');
	if (pos == -1) b[2] = 0;
	else {
		c = a.substr(0, pos + 1);
		c.erase(--c.end());//忽略x 
		if (c == "+") b[2] = 1;
		else if (c == "-") b[2] = -1;//特判正负1 
		else b[2] = atof(c.c_str());//求b的系数 
	}
	if (pos == -1) b[3] = atof(a.c_str());
	else if (pos == a.size()) b[3] = 0;
	else c = a.substr(pos + 1), b[3] = atof(c.c_str());//求c的系数 
	//cout << b[1] << ' ' << b[2] << ' ' << b[3];
	x2 = (-b[2] + sqrt(b[2] * b[2] - 4 * b[1] * b[3])) / b[1] / 2;
	x1 = (-b[2] - sqrt(b[2] * b[2] - 4 * b[1] * b[3])) / b[1] / 2;//求根 
	//cout << x1 << ' ' << x2;
	if (x1 == x2) work(-x1), cout << "^2";
	else work(-x1), work(-x2);
}

Content

输入一个多项式 x2+ax+bx2+ax+b(不保证 a,b≠0a,b=0),请对这个多项式进行因式分解(形式为 (x−x1)(x−x2)(x−x1​)(x−x2​),其中 x1>x2x1​>x2​)。

数据范围:a,b<231a,b<231。

Solution

这道题目看上去很简单,做起来却有很多的细节要注意。

首先,我们可以得到一个大致的思路:得到 a,ba,b 之后利用求根公式求出 x1,x2x1​,x2​:

x1,2=−a±a2−4b2x1,2​=2−a±a2−4b​​

当然,这是按照题目进行变化后得到的式子,我想你们应该都熟悉这个:−b±b2−4ac2a2a−b±b2−4ac​​,但因为保证了二次项系数是 11,所以没什么必要。

那么完了以后,我们的因式分解的结果就是 (x−x1)(x−x2)(x−x1​)(x−x2​),当然,首先如果 x1<x2x1​<x2​,就得要交换。输出的时候分以下三种情况讨论:

  • x<0x<0,此时因为前面已经带了负号,所以直接用 printf("(x%d)", x) 就好。
  • x=0x=0,此时直接输出 x
  • x>0x>0,此时用 printf("(x+%d)", x) 输出。

总体来讲就是以上这些操作,还需注意一下将 a,ba,b 从字符串中提取出来的问题,具体请读者看代码自行理解。

Code

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
using namespace std;

string s;
double a, b, flagx, f, now;

void print(int xx) {
	if(xx < 0)	printf("(x%d)", xx);
	else if(!xx)	printf("x");
	else	printf("(x+%d)", xx);
}

int main() {
	cin >> s;
	int n = s.size();
	f = 1;
	for(int i = 3; i < n; ++i)
		if(s[i] == 'x')	flagx = 1;
	if(!flagx) {
		now = 0;
		for(int i = 3; i < n; ++i) {
			if(s[i] == '-')	f *= -1;
			else if(isdigit(s[i]))	now = now * 10 + s[i] - '0';
		}
		b = f * now;
	} else {
		now = 0;
		for(int i = 3; i < n; ++i) {
			if(s[i] == 'x' && i == 3) {
				a = 1;
				now = 0, f = 1;
			} else if(s[i] == 'x' && i > 3) {
				a = now * f;
				now = 0; f = 1;
			} else if(s[i] == '-')	f *= -1;
			else if(isdigit(s[i]))	now = now * 10 + s[i] - '0';
//			printf("now=%d\n\n", now);
		}
		b = f * now;
	}
	double x1 = -(-a + sqrt(a * a - 4 * b)) / 2, x2 = -(-a - sqrt(a * a - 4 * b)) / 2;
//	printf("%d %d %d %d\n", a, b, x1, x2);
	if(x1 == x2) {
		print(x1);
		printf("^2");
	} else {
		if(x1 < x2)	swap(x1, x2);
		print(x1), print(x2);
	}
	return 0;
}

多项式乘法

P2553 [AHOI2001] 多项式乘法 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目描述

请编程序把含有乘法运算的代数多项式表达式改写成不含乘法的代数多项式。为简化计算,特做以下约定:

  1. 代数多项式表达式中只涉及一个代数符号 a
  2. 保证输入的「含乘法运算的代数多项式」有且仅有一个「代数多项式」与「代数多项式」的乘法。形式化地讲,每一个测试点的输入数据中,一定有且仅有一行 (...)*(...),其中 ... 为不含乘法运算的代数多项式。
  3. 一个「不含乘法运算的代数多项式」会被写作 XXXa^YYY+XXXa^YYY+XXXa^YYY+...+XXX(代表 XXXaYYY+XXXaYYY+XXXaYYY+⋯+XXXXXXaYYY+XXXaYYY+XXXaYYY+⋯+XXX),其中 XXXYYY 均为正整数,且保证除第一项外每一项的 YYY 比上一项的 YYY 少 11。例如,一个合法的「不含乘法运算的代数多项式」为 142a^4+9a^3+4a^2+1a^1+3

对于约定 3,原题目给予了这样一个表述:常数项以外的各项都是 xayxay 的形式,写作 xa^y,其中 xx 为该项的系数,而 yy 是该项的指数。x=1x=1 时,不得简写成 a^y,应写成 1a^y。而 y=1y=1 时,不得简写成 xa,应写成 xa^1

输入格式

输入仅有一行字符串,代表给定的「含乘法运算的代数多项式」。

其格式为:(...)*(...),其中 ... 为不含乘法运算的代数多项式。对于「不含乘法运算的代数多项式」的约束,请参考题目描述。

输出格式

输出一行一个字符串,代表答案。

答案要求指数大的项不能出现在指数小的项之后,指数相同的项必须合并同类项。不允许出现不必要的空白字符。输出中不允许有括号。

输入输出样例

输入 #1复制

(5a^2+3a^1+2)*(4a^1+1)
(5a^1+1)* (5a^1+1)

输出 #1复制

20a^3+17a^2+11a^1+2
25a^2+10a^1+1

说明/提示

关于数据范围以及数据若干格式的说明:

  • 系数范围和指数范围均为 [0,30][0,30]。

看到题第一眼,就知道这是个暴力处理多项式然后用fft搞就行了。。。

但是有许多坑点,比如输入字符串中没有'*'就什么也不输出题目就™不能讲清楚吗

因为这个WA了好几次,又因为只有一个数据点,每次都提示输出多了,我也看不了别人代码对一下。。。

最后在网上找了一个博客,试了几组数据都正确并且ta还不能处理没有括号的情况

看到ta的代码中有一行:

if(ppos == std::string::npos) continue;

 这是干啥啊大兄弟。。。似乎是判断有没有'*'?

然后加上就过了。。。这种垃圾题还是别出了QAQ

代码:

# include<iostream>
# include<cstring>
# include<cstdio>
# include<cmath>
using namespace std;
const int MAX=1e6+1;
const double Pi=acos(-1.0);
struct complex{
	double x,y;
	complex(double X=0,double Y=0){x=X,y=Y;}
}a[2][MAX];
int n,m,l,lim=1;
int r[MAX],len[MAX],ans[MAX];
complex operator+ (complex x,complex y)
{
	return complex(x.x+y.x,x.y+y.y);
}
complex operator- (complex x,complex y)
{
	return complex(x.x-y.x,x.y-y.y);
}
complex operator* (complex x,complex y)
{
	return complex(x.x*y.x-x.y*y.y,x.x*y.y+x.y*y.x);
}
void fft(complex *A,int tt)
{
	for(int i=0;i<lim;++i)
	  if(i<r[i]) swap(A[i],A[r[i]]);
	for(int i=1;i<lim;i<<=1)
	  {
	  	complex w1(cos(Pi/i),tt*sin(Pi/i));
		for(int l=i<<1,j=0;j<lim;j+=l)
		  {
	  		complex w(1,0);
	  		for(int k=0;k<i;++k,w=w*w1)
	  		  {
	  		  	complex x=A[j+k],y=w*A[j+i+k];
	  		  	A[j+k]=x+y,A[j+i+k]=x-y;
			  }
	  	  }
	  }
	if(tt==-1)
	for(int i=0;i<lim;++i)
	  A[i].x=(int)(A[i].x/lim+0.5);
}
int main()
{
	string s;
	while(getline(cin,s))
	{
		bool fl=0;
		int L=s.length(),num=0;
		for(int i=0;i<L;++i)
		  if(s[i]=='*')
		  {
		  	fl=1;
		  	break;
		  }
		if(!fl) continue;
		memset(a,0,sizeof(a));
		memset(len,0,sizeof(len));
		memset(ans,0,sizeof(ans));
		for(int i=0,tt=0;i<L;i+=tt)
		  {
		  	tt=0;
		  	int x=0;
		  	if(isdigit(s[i]))
			{
				int j=i;
		  		while(isdigit(s[j])) ++tt,x=x*10+s[j++]-48;
		  		while(s[j]==' ') ++j;
		  		if(s[j]=='a')
		  		{
		  			j+=2,tt+=2;
		  			int y=0;
		  			while(isdigit(s[j])) ++tt,y=y*10+s[j++]-48;
		  			len[num]=max(len[num],y);
					a[fl][y].x+=x;
				}
				else if(s[j]=='+'||s[j]==')'||s[j]=='*'||j==L) a[fl][0].x+=x;
			}
			if(s[i]=='*'||i+(tt?tt:1)-1==L-1)
			{
				if(s[i]=='*') ++tt;
				if(num>=1)
				{
					lim=1,l=0;
					memset(r,0,sizeof(r));
					while(lim<=len[num]+len[num-1]) lim<<=1,++l;
					for(int j=0;j<lim;++j)
					  r[j]=(r[j>>1]>>1)|((j&1)<<(l-1));
					fft(a[fl],1),fft(a[fl^1],1);
					for(int j=0;j<=lim;++j)
					  a[fl][j]=a[fl][j]*a[fl^1][j];
					fft(a[fl],-1);
					for(int j=0;j<=lim;++j)
					  a[fl][j].y=a[fl^1][j].y=a[fl^1][j].x=0;
					len[num]=len[num]+len[num-1];
				}
				++num,fl^=1;
			}
			if(!tt) ++tt;
		  }
		bool gg=0;
		for(int j=0;j<=len[num]+len[num-1];++j)
		  {
		  	ans[j]+=a[fl^1][j].x;
		  	if(a[fl^1][j].x!=0) gg=1;
		  }
		if(!gg)
		{
			printf("0\n");
			continue;
		}
		int Len1=0,Len2=0;
		for(int i=0;!ans[i];++i)
		  ++Len1;
		Len2=Len1;
		for(int i=Len1+1;ans[i]!=0;++i)
		  ++Len2;
		if(Len2!=Len1) printf("%da^%d",ans[Len2],Len2);
		for(int i=Len2-1;i>Len1;--i)
		  printf("+%da^%d",ans[i],i);
		if(!Len1)
		{
			if(Len2) printf("+%d\n",ans[0]);
			else printf("%d\n",ans[0]);
		}
		else
		{
			if(Len2!=Len1) printf("+%da^%d\n",ans[Len1],Len1);
			else printf("%da^%d\n",ans[Len1],Len1);
		}
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值