题目链接:https://pintia.cn/problem-sets/994805046380707840/problems/994805060372905984
L2-018 多项式A除以B
这仍然是一道关于A/B的题,只不过A和B都换成了多项式。你需要计算两个多项式相除的商Q和余R,其中R的阶数必须小于B的阶数。
输入格式:
输入分两行,每行给出一个非零多项式,先给出A,再给出B。每行的格式如下:
N e[1] c[1] … e[N] c[N]
其中N是该多项式非零项的个数,e[i]是第i个非零项的指数,c[i]是第i个非零项的系数。各项按照指数递减的顺序给出,保证所有指数是各不相同的非负整数,所有系数是非零整数,所有整数在整型范围内。
输出格式:
分两行先后输出商和余,输出格式与输入格式相同,输出的系数保留小数点后1位。同行数字间以1个空格分隔,行首尾不得有多余空格。注意:零多项式是一个特殊多项式,对应输出为0 0 0.0。但非零多项式不能输出零系数(包括舍入后为0.0)的项。在样例中,余多项式其实有常数项-1/27,但因其舍入后为0.0,故不输出。
输入样例:
4 4 1 2 -3 1 -1 0 -1
3 2 3 1 -2 0 1
输出样例:
3 2 0.3 1 0.2 0 -1.0
1 1 -3.1
题目分析
本题主要有3个需要考虑的点:
- 多项式的除法运算
- 数据结构的选择
- 保留1位小数后,有效数值的处理
一、首先解决多项式除法问题
多项式的除法简单的来说,就是每次运算凑出被除数的最高次方的项,然后就能一次次的将被除数的最高次方给降下来,直到最高次方小于除数的次方。
拿题目的样例来说:
被除数:
x
4
−
3
x
2
−
x
−
1
x^{4}-3 x^{2}-x-1
x4−3x2−x−1
除数:
3
x
2
−
2
x
+
1
3x^{2}-2x+1
3x2−2x+1
被除数最大次方的项是
x
4
x^{4}
x4 那就凑出来,将除数乘上一个
1
3
x
2
\frac{1}{3} x^{2}
31x2
同理,再次凑出最大次方的项,只需要乘上一个
2
9
x
\frac{2}{9}x
92x
一样的,最后我们乘上一个
−
26
27
-\frac{26}{27}
−2726 就是最后的答案了
题目要求进行保留1位小数所以结果就是:
商:
0.3
x
2
+
0.2
x
−
1.0
0.3x^{2}+0.2x-1.0
0.3x2+0.2x−1.0
余数:
−
3.1
x
−
0.0
-3.1x-0.0
−3.1x−0.0
二、其次解决数据结构选择的问题
本题数据结构的选择有很多种,我采用的是两个数组 e[] 和 c[] 分别保存指数和系数
但是其实你也可以使用 Map 容器来保存,key就是指数,value是系数;或者如果你不知道如何使用Map,那你也可以使用结构体+数组的方式,总的来说,数据结构有着很多的选择,不同的数据结构处理起来也有不同的方式。
三、最后解决保留小数1位小数的问题
题目要求保留1位小数,并且是经过舍入后的结果,如果你使用的是C语言的
printf("%.1lf")
那么你就不需要考虑舍入的问题,这种方式会自动四舍五入。
如果你不是使用这种方式舍入,那么你可以对输出的结果加上一个0.05,然后保留1位小数,这样也能起到四舍五入的效果。
AC代码:
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int e[3][50000]; // 指数
double c[3][50000]; // 系数
int a[50000]; // 辅助数组
double b[50000]; // 辅助数组
void run(int id, int n) { // 处理最后的结果,并输出
int allN = 0;
for(int i=0;i<n;i++) { // 过滤无效值,并且重新确定项数
if(fabs(c[id][i]) > 0.04) {
a[allN] = e[id][i];
b[allN++] = c[id][i];
}
}
if(allN == 0) {
cout<<"0 0 0.0"<<endl;
} else {
cout<<allN<<" ";
for(int i=0;i<allN-1;i++){
printf("%d %.1lf ", a[i], b[i]);
}
printf("%d %.1lf\n", a[allN-1], b[allN-1]);
}
}
int main(int argc, char *argv[]) {
int n1,n2;
cin>>n1;
for(int i=0;i<n1;i++) { // 输入被除数
cin>>e[0][i]>>c[0][i];
}
cin>>n2;
for(int i=0;i<n2;i++) { // 输入除数
cin>>e[1][i]>>c[1][i];
}
int id = 0; // 标记被除数最大次方
int sum = 0;// 记录运算了几次
while(e[0][id] >= e[1][0]) { // 循环条件:被除数最大次方>=除数最大次方
double rt[2][50000]; // 缓存减数
double result[2][50000]; // 对减结果
int i,j,s=0; // s是对减结果新的项数
// 凑出最大项要乘的数
e[2][sum] = e[0][id] - e[1][0];
c[2][sum] = c[0][id] / c[1][0];
for(i=0;i<n2;i++) { // 得出减数
rt[0][i] = e[2][sum]+e[1][i];
rt[1][i] = c[2][sum]*c[1][i];
}
i = 0;
j = 0;
while(i < n1 && j < n2) { // 归并的思想进行对减,保证次幂从大到小
while(i < n1 && c[0][i] == 0) { // 排除系数为0的情况
i++;
}
if(i >= n1) break;
if(rt[0][j] == e[0][i]) {
result[0][s] = e[0][i];
result[1][s++] = c[0][i] - rt[1][j];
i++;
j++;
} else if(rt[0][j] > e[0][i]) {
result[0][s] = rt[0][j];
result[1][s++] = -rt[1][j];
j++;
} else {
result[0][s] = e[0][i];
result[1][s++] = c[0][i];
i++;
}
}
while(j < n2) {
result[0][s] = rt[0][j];
result[1][s++] = -rt[1][j++];
}
while(i < n1) {
result[0][s] = e[0][i];
result[1][s++] = c[0][i++];
}
int res = -1; // 标记有效的最大次方项的下标(因为有系数为0的项)
for(i=0;i<s;i++) {
e[0][i] = result[0][i];
c[0][i] = result[1][i];
if(res < e[0][i] && c[0][i] != 0) {
res = e[0][i];
id = i;
}
}
n1 = s;
sum++;
if(res == -1) {
break;
}
}
run(2, sum);
run(0, n1);
return 0;
}
温馨提示:注意输出格式问题,末尾不要有多余的空格。