1002 A+B for Polynomials(模拟,多项式相加)

1002 A+B for Polynomials

0、题目

This time, you are supposed to find A + B A+B A+B where A A A and B B B are two polynomials.

Input Specification:

Each input file contains one test case. Each case occupies 2 lines, and each line contains the information of a polynomial:

K N 1 a N 1 N 2 a N 2 . . . N K a N K K N_1 a_{N_1} N_2 a_{N_2} ... N_K a_{N_K} KN1aN1N2aN2...NKaNK

where K K K is the number of nonzero terms in the polynomial, N i N_i Ni and a N i a_{N_i} aNi ( i = 1 , 2 , ⋯ , K i=1,2,⋯,K i=1,2,,K) are the exponents and coefficients, respectively. It is given that 1 ≤ K ≤ 10 1≤K≤10 1K10 0 ≤ N K < ⋯ < N 2 < N 1 ≤ 1000 0≤N_K<⋯<N_2<N_1≤1000 0NK<<N2<N11000.

Output Specification:

For each test case you should output the sum of A A A and B B B in one line, with the same format as the input. Notice that there must be NO extra space at the end of each line. Please be accurate to 1 decimal place.

Sample Input:

2 1 2.4 0 3.2
2 2 1.5 1 0.5

Sample Output:

3 2 1.5 1 2.9 0 3.2

1、大致题意

一定要理解题意!!样例中每行代表一个多项式,每行的第一个数代表该多项式有几项,然后每两个数字分别代表第几项以及它对应的系数。左后将给出的两个多项式相加。

2、基本思路

很自然的想到了用 map来做,key 是次数,value 是系数,想偷懒不用自己管理这个数组,但后面遇到了三个坑。

3、解题过程

3.1 map的相关操作

既然选择用 STL偷懒大法,就一定要记住其中的相关操作,在做这道题前我整理了map的重要操作,这道题里面主要用到了以下两个。

3.1.1 判断 map的 key 中的值有没有出现过
3.1.1.1 count()函数

count函数用于统计key值在map中出现的次数,map的key不允许重复, 存在返回1,不存在返回0

map.count(key)==0
3.1.1.2 find函数

如果key存在,则find返回key对应的迭代器,如果key不存在, 则find返回尾后迭代器.end()

map.find(key)==map.end()
3.1.2 使得 map按照一定规则排序

这道题里主要是为了使多项式可以降序排列。

3.1.2.1 map按key排序
3.1.2.1.1 map默认按照 key 从小到大排序
 map<string,int> hash;
 等价于 map<string,int, less<string>> hash;

其他的格式自己推即可,有的编译器会不允许 less<string>>的两个 >>连在一起,记得分开

map<int,double,greater<int> >ma;
3.1.2.1.2 map默认按照 key 从小到大排序
map<string,int, greater<string> > hash;
3.1.2.2 map按value排序

很可惜,按 value 值排序没有直接的方法。

但我们可以把 map 存到 vector 中,再对 vector 进行自定义排序,因为 vector 是可以借助 cmp随意排序的,所以这里以 value 值从小到大排序为例

3.1.2.2.1 写法一

定义 vectorcmp函数

bool cmp(pair<string,int> a, pair<string, int> b) {
    return a.second < b.second;
}

map存到 vector中进行排序

map<string,int> m;
m["you"] = 2;
m["we"] = 3;
m["they"] = 1;

vector<pair<string,int> > vec(m.begin(),m.end());
sort(vec.begin(),vec.end(),cmp);
3.1.2.2.2 写法二

遍历 map,把键值对取出来放到一个vector<vector<int>> tmp里面,然后对 tmp排序

vector<vector<int>> tmp;
for (auto x : hash) tmp.push_back({x.first, x.second});
sort(tmp.begin(), tmp.end(), [](vector<int> a, vector<int> b){return a[1] > b[1];});
3.1.2.2.3 示例代码
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
using namespace std;

bool cmp(pair<string,int> a, pair<string, int> b) {
    return a.second < b.second;
}

int main() {
    map<string,int> m;
    m["you"] = 2;
    m["we"] = 3;
    m["they"] = 1;
  
    vector<pair<string,int> > vec(m.begin(),m.end());
    sort(vec.begin(),vec.end(),cmp);
    
    cout << "Map 存到 vector 后按 value 从小到大排序" << endl;
    for (auto x : vec) cout << x.first << " " << x.second << endl;

    return 0;
}
3.1.1.3 第一份代码
#include<iostream>
#include<map>
#include<cmath>
using namespace std;
int K;
map<int,double,greater<int> >ma;

int main() {
	ma.clear();
	cin>>K;
	int a,minn=99999999;
	double b;

	for(int i=0; i<K; i++) {
		cin>>a>>b;
		if(ma.count(a)==0) {
			ma[a]=b;
			minn=min(a,minn);
		} else {
			ma[a]+=b;
		}
	}
	cin>>K;
	for(int i=0; i<K; i++) {
		cin>>a>>b;
		if(ma.count(a)==0) {
			ma[a]=b;
			minn=min(a,minn);
		} else {
			ma[a]+=b;
		}
	}
	cout<<ma.size()<<" ";
	for(map<int,double>::iterator it=ma.begin(); (it)!=ma.end(); it++) {
		if(it->first!=minn) {
			cout<<it->first<<" "<<it->second<<" ";
		} else {
			cout<<it->first<<" "<<it->second<<endl;
		}
	}
	return 0;
}

第一份代码得了15分,对了第一个和第三个用例。

在这里插入图片描述

3.2 小数点位数问题

提交完就马上反应过来,没有把 多项式的系数 变成1位小数

3.2.1 I/O的格数处理

不得不讲到一个头文件 #include<iomanip>

其中 io代表输入输出,manipmanipulator(操纵器)的缩写(在c++上只能通过输入缩写才有效)。主要是对 cincout之类的一些操纵运算子,比如 setfillsetwsetbasesetprecision等等。它是 I/O流控制头文件,就像 C 里面的格式化输出一样。以下是一些常见的控制函数的介绍:

控 制 符作 用
dec设置整数为十进制,相当于"%d"
hex设置整数为十六进制,相当于"%X"
oct设置整数为八进制,相当于"%o"
setbase(n)设置整数为n进制(n=8,10,16)
setfill(n)设置字符填充,n可以是字符常或字符变量
setprecision(n)设置浮点数的有效数字为n位
setw(n)设置字段宽度为n位
setiosflags(ios::fixed)设置浮点数以固定的小数位数显示
setiosflags(ios::scientific)设置浮点数以科学计数法表示
setiosflags(ios::left)输出左对齐
setiosflags(ios::right)输出右对齐
setiosflags(ios::skipws)忽略前导空格
setiosflags(ios::uppercase)在以科学计数法输出E与十六进制输出X以大写输出,否则小写。
setiosflags(ios::showpos)输出正数时显示"+"号
setiosflags(ios::showpoint)强制显示小数点
resetiosflags()终止已经设置的输出格式状态,在括号中应指定内容
3.2.2 提高二分

在这道题里主要在输出的部分需要注意。

for(map<int,double>::iterator it=ma.begin(); (it)!=ma.end(); it++) {
    cout<<" "<<it->first<<" "<<setiosflags(ios::fixed)<<setprecision(1)<<it->second;
}

代码修改之后

#include<iostream>
#include<map>
#include<cmath>
#include<iomanip>
using namespace std;
int K;
map<int,double,greater<int> >ma;

int main() {
	ma.clear();
	int a,minn=99999999;
	double b;
	cin>>K;
	for(int i=0; i<K; i++) {
		cin>>a>>b;
		if(ma.count(a)==0) {
			ma[a]=b;
			minn=min(a,minn);
		} else {
			ma[a]+=b;
		}
	}
	cin>>K;
	for(int i=0; i<K; i++) {
		cin>>a>>b;
		if(ma.count(a)==0) {
			ma[a]=b;
			minn=min(a,minn);
		} else {
			ma[a]+=b;
		}
	}
	if((int)ma.size()==0) {
		cout<<0<<endl;
	} else {
		cout<<ma.size()<<" ";
		for(map<int,double>::iterator it=ma.begin(); (it)!=ma.end(); it++) {
			if(it->first!=minn) {
				cout<<it->first<<" "<<setiosflags(ios::fixed)<<setprecision(1)<<it->second<<" ";
			} else {
				cout<<it->first<<" "<<setiosflags(ios::fixed)<<setprecision(1)<<it->second<<endl;
			}
		}
	}
	return 0;
}

提高了两分

在这里插入图片描述

成功增加了两分。

3.3 本题的天坑

还有一个坑在于如果你输入的用例是

1 1 -1
1 1 1

按照上一份代码,系数为零也会输出,同时多项式的数量也不对,导致错误。

#include<iostream>
#include<map>
#include<cmath>
#include<iomanip>
using namespace std;
int K;
map<int,double,greater<int> >ma;

int main() {
//	while(1) {
	ma.clear();
	int a;
	double b;
	cin>>K;
	for(int i=0; i<K; i++) {
		cin>>a>>b;
		if(ma.count(a)==0&&b!=0) {
			ma[a]=b;
		} else {
			ma[a]+=b;
		}
	}
	cin>>K;
	for(int i=0; i<K; i++) {
		cin>>a>>b;
		if(ma.count(a)==0&&b!=0) {
			ma[a]=b;
		} else {
			ma[a]+=b;
		}
	}
	for(map<int,double>::iterator it=ma.begin(); (it)!=ma.end(); it++) {
		if(it->second==0){
			ma.erase(it);
		}
	}
	if((int)ma.size()==0) {
		cout<<0<<endl;
	} else {
		cout<<ma.size();
		for(map<int,double>::iterator it=ma.begin(); (it)!=ma.end(); it++) {
			cout<<" "<<it->first<<" "<<setiosflags(ios::fixed)<<setprecision(1)<<it->second;
		}
		cout<<endl;
	}
//	}
	return 0;
}

在这里插入图片描述

出现段错误,又是 .size().end()函数上的问题,在 1001 中遇到过。

首先,要是在vector中这样子写是没有问题的,例如:

for(vector<int>::iterator it = vecInt.begin(); it != vecInt.end();) {
    if(*it == 0) {
        it = vecInt.erase(it);
    }
    else {
        it++;
    }
}

从一个 vector 中删除值为 0 的元素,利用了 vector::erase 函数根据 iterator 删除某个元素时会返回下一个元素的 iterator 的性质:http://www.cplusplus.com/reference/vector/vector/erase/

但是 map 并不一样,C++98中 map::erase 并没有返回值为 iterator 的原型函数,那么 it=map.erase(it) 然后对 it 进行操作会发生什么呢?在执行 map.erase(it) 之后,it 这个 iterator 已经失效了,考虑C语言中一个失效释放了的指针,再次引用它会导致段错误,具体可以看http://www.cplusplus.com/reference/map/map/erase/ 上的说明。在循环中正确使用 map::erase 的方法如下:

for(map<int,int>::iterator it = mapInt.begin(); it != mapInt.end();) {
    if(it->second == 0) {
        mapInt.erase(it++);
    }
    else {
        it++;
    }
}

3.4 AC代码

#include<iostream>
#include<map>
#include<cmath>
#include<iomanip>
using namespace std;
int K;
map<int,double,greater<int> >ma;

int main() {
	ma.clear();
	int a;
	double b;
	cin>>K;
	for(int i=0; i<K; i++) {
		cin>>a>>b;
		if(ma.count(a)==0&&b!=0) {
			ma[a]=b;
		} else {
			ma[a]+=b;
		}
	}
	cin>>K;
	for(int i=0; i<K; i++) {
		cin>>a>>b;
		if(ma.count(a)==0&&b!=0) {
			ma[a]=b;
		} else {
			ma[a]+=b;
		}
	}
	for(map<int,double>::iterator it=ma.begin(); (it)!=ma.end();) {
		if(it->second==0){
			ma.erase(it++);
		}else{
			++it;
		}
	}
	if(ma.empty()) {
		cout<<0<<endl;
	} else {
		cout<<ma.size();
		for(map<int,double>::iterator it=ma.begin(); (it)!=ma.end(); it++) {
			cout<<" "<<it->first<<" "<<setiosflags(ios::fixed)<<setprecision(1)<<it->second;
		}
		cout<<endl;
	}
	return 0;
}

在这里插入图片描述

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 好的,以下是关于多项式加法的解答: 多项式是一种数学表达式,其中包含了一个或多个变量的项,每个项包括了一个系数和指数。多项式的加法是将两个多项式相加,使得同一指数的项相加并合并同类项。 例如,考虑以下两个多项式: a = 3x^2 + 2x + 1 b = 5x^3 + 2x^2 - 3x + 4 它们的和为: a + b = 5x^3 + 5x^2 - x + 5 为了实现多项式加法,我们可以使用类似于整数加法的算法。首先,我们按照指数从高到低的顺序将两个多项式的项进行排列,并合并同类项。然后,将同一指数的项的系数相加,并创建一个新的多项式来表示它们的和。 以下是一个用 Python 实现多项式加法的示例代码: ```python def add_polynomials(a, b): result = {} for exponent, coefficient in a.items(): result[exponent] = coefficient + result.get(exponent, 0) for exponent, coefficient in b.items(): result[exponent] = coefficient + result.get(exponent, 0) return {k: v for k, v in sorted(result.items(), reverse=True)} ``` 在这个函数中,我们使用一个字典来表示多项式。字典的键是多项式中每个项的指数,而值是该项的系数。我们首先遍历多项式 a 的每个项,并将其系数添加到结果字典中相应指数的项中。然后,我们再遍历多项式 b 的每个项,并将其系数添加到结果字典中相应指数的项中。最后,我们将结果字典按照指数从高到低的顺序排序,并返回结果。 例如,我们可以使用以下代码来测试上面的函数: ```python a = {2: 3, 1: 2, 0: 1} b = {3: 5, 2: 2, 1: -3, 0: 4} print(add_polynomials(a, b)) # 输出:{3: 5, 2: 5, 1: -1, 0: 5} ``` 这个例子中,我们将多项式 a 和 b 传递给 `add_polynomials` 函数,并打印函数的返回值。函数返回的结果是一个字典,其中包含了相加后的多项式的各项系数。 希望这可以回答你的问题! ### 回答2: 我们考虑两个多项式P(x)和Q(x),并给予它们各自的次数a和b。那么,首先我们要确定它们的乘积,也就是P(x)乘以Q(x)。我们可以通过分配律将乘积展开,得到一个系数为c_i的新多项式R(x): P(x) * Q(x) = R(x) = c_0 + c_1x + c_2x^2 + ... + c_{a+b}x^{a+b} 其中,c_i表示x的i次项的系数。为了计算出这些系数,我们需要对所有次数小于或等于a+b的i进行求和。具体来说,我们可以使用下面这个公式: c_i = sum(j=0 to i) P(j) * Q(i-j) 也就是说,第i项的系数是将第一个多项式中次数小于或等于j的项和第二个多项式中次数等于i-j的项相乘,并且对所有j求和。我们可以使用循环来计算这些系数。 需要注意的是,由于两个非零多项式的乘积的次数至少为a+b,因此我们需要为求和循环的上界设置一个适当的值。具体来说,可以将循环的上界设置为a+b,这样就能保证所有的系数都会被计算。此外,如果某个系数为0,则可以将它省略掉,以减少计算量。 在实现时,还需要注意多项式乘法中的一些细节。例如,当某个多项式的系数为0时,我们可以假定它的所有次数都对应了一个系数为0的项。此外,我们需要考虑多项式乘法的精度,以避免出现浮点数误差。具体来说,可以使用一些特殊的技巧来避免浮点数误差,例如将系数表示为有理数,或者使用任意精度计算库。 总之,多项式乘法是非常基础的数学问题,也是很多算法和应用程序的核心部分。通过合理地选择算法和编写高效的代码,我们可以在计算多项式乘法时获得比较优秀的性能。 ### 回答3: 题意: 给定两个多项式 $A(x)$ 和 $B(x)$,请求出它们的乘积 $C(x)$ 思路: 多项式乘法非常简单,就是按照手算乘法的规则将每一项相乘然后相加。但是对于两个多项式相乘,需要循环枚举每一项相乘,最终将结果相加。如果直接按照手算乘法来做会有很多重复的计算,因此需要使用一些技巧来优化计算过程。下面给出两种常见的优化方法: 方法一:常规乘法过程 对于两个多项式 $A(x) = a_0 x^0 + a_1 x^1 + ... + a_n x^n$ 和 $B(x) = b_0 x^0 + b_1 x^1 + ... + b_m x^m$,它们的乘积可以表示为 $$C(x) = A(x) \cdot B(x) = c_0 x^0 + c_1 x^1 + ... + c_{n+m} x^{n+m}$$ 其中 $c_k$ 是 $A(x)$ 中所有次数为 $i$ 的项和 $B(x)$ 中所有次数为 $k-i$ 的项的乘积之和,即 $$c_k = \sum_{i=0}^{k} a_i b_{k-i}$$ 对于每一个 $k$,需要循环枚举 $i$ 的值,这样时间复杂度就是 $O(nm)$,无法通过本题。 方法二:多项式快速幂 快速幂是一种用来计算 $a^n$ 的算法,可以将计算次数从 $O(n)$ 优化到 $O(\log n)$,非常高效。对于两个多项式 $A(x)$ 和 $B(x)$,它们的乘积可以表示为 $$C(x) = A(x) \cdot B(x)$$ 令 $A(x) = A_0(x) + A_1(x) x^{\frac{n}{2}}, B(x) = B_0(x) + B_1(x) x^{\frac{n}{2}}$,其中 $n$ 是 $A(x)$ 和 $B(x)$ 最高次项次数加一并且是 $2$ 的幂次方,$A_0(x)$ 和 $B_0(x)$ 是 $A(x)$ 和 $B(x)$ 中次数不大于 $\frac{n}{2}$ 的项组成的多项式,$A_1(x)$ 和 $B_1(x)$ 是 $A(x)$ 和 $B(x)$ 中次数大于 $\frac{n}{2}$ 的项组成的多项式,即 $$A(x) = A_0(x) + x^{\frac{n}{2}} A_1(x)$$ $$B(x) = B_0(x) + x^{\frac{n}{2}} B_1(x)$$ 则有 $$C(x) = A(x) \cdot B(x) = A_0(x) B_0(x) + x^n A_1(x) B_1(x) + x^{\frac{n}{2}} (A_0(x) B_1(x) + A_1(x) B_0(x))$$ 我们可以首先递归计算以下三个多项式: $$C_0(x) = A_0(x) \cdot B_0(x)$$ $$C_1(x) = A_1(x) \cdot B_1(x)$$ $$C_2(x) = (A_0(x) + A_1(x)) \cdot (B_0(x) + B_1(x))$$ 然后将它们合并成最终结果,即 $$C(x) = C_0(x) + x^n C_1(x) + x^{\frac{n}{2}} (C_2(x) - C_0(x) - C_1(x))$$ 这样可以将时间复杂度优化到 $O(n \log n)$,可以通过本题。 AC CODE:
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值