洛谷 - P2281 - 多项式的加法和乘法 - 大模拟
题目链接:https://www.luogu.org/problemnew/show/P2281
题目的意思很简单,输入两个系数、指数都是整数,变量都是大写字母的多项式,求他们的加法结果和乘法结果。
按照题目的意思模拟,先设计我们需要的类。
单项式
一个单项式由系数以及各个变量的指数组成,为了简单起见他们都是带符号数。
多项式
一个多项式由一个单项式的向量组成。
然后实现一些细节就可以了:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct Mo {
//单项式由两个部分组成:带符号的系数+字母和带符号的指数
ll xs; //单项式的系数
ll zs[256]; //单项式的指数
Mo() {
xs=0;
memset(zs,0,sizeof(zs));
}
//单项式的小于序,按题目要求,从A到Z,从小到大排序
bool operator<(Mo &m) {
for(int i='A'; i<='Z'; i++) {
if(zs[i]!=m.zs[i]) {
return zs[i]<m.zs[i];
} else {
continue;
}
}
//为确定严格的小于序,规定指数相同的按系数排列
return xs<m.xs;
}
//指示两个单项式能否合并同类项
bool canMerge(Mo &m) {
//能够合并,前提是指数都相同
for(int i='A'; i<='Z'; i++) {
if(zs[i]!=m.zs[i]) {
return false;
} else {
continue;
}
}
return true;
}
//单项式的乘法,系数相乘,对应指数相加
Mo operator*(Mo &m) {
Mo ret;
ret.xs=xs*m.xs;
for(int i='A'; i<='Z'; i++) {
ret.zs[i]=zs[i]+m.zs[i];
}
return ret;
}
//单项式的带符号输出,即使在多项式的开头也输出符号
string toString() {
if(xs==0) {
//多项式不应该有系数为0的单项式,都进入这里了直接RE吧,为0的项在读入和加法的时候应被消除
exit(-1);
return "";
}
string ans="";
char tmp[25]; //用来把数字转成字符串
if(xs>0) {
//系数为正,加入单项式前的加号
ans+="+";
if(xs>1) {
//非1的系数必须打印
sprintf(tmp,"%lld",xs);
ans+=string(tmp);
}
} else {
//负数自带符号,但-1不输出那个1,就单输出一个负号
if(xs==-1) {
ans+="-";
} else {
//非-1的系数必须打印
sprintf(tmp,"%lld",xs);
ans+=string(tmp);
}
}
int nozs=1; //指示这个多项式是否 没有指数非零
for(int i='A'; i<='Z'; i++) {
if(zs[i]!=0) {
nozs=0; //有指数非零
//指数非0,输出该字母
ans+=(char)(i);
if(zs[i]!=1) {
//指数非1,额外输出指数,负数也一样可以输出
ans+="^";
sprintf(tmp,"%lld",zs[i]);
ans+=string(tmp);
}
}
}
if(nozs) {
//没有指数非零,这个是常数项
if(abs(xs)==1)
//常数项的正负1要输出
ans+="1";
}
return ans;
}
};
struct Poly {
//存放单项式的向量
vector<Mo> v;
Poly() {}
//加法,两个多项式的单项式堆在一起,合并同类项
Poly operator+(Poly p) {
Poly ret;
for(auto vi:v) {
ret.v.push_back(vi);
}
for(auto vi:p.v) {
ret.v.push_back(vi);
}
ret.Merge();
return ret;
}
//乘法,二维遍历每个单项式,乘在一起,然后堆在一起合并同类项
Poly operator*(Poly p) {
Poly ret;
for(auto vi:v) {
for(auto vpi:p.v) {
ret.v.push_back(vi*vpi);
}
}
ret.Merge();
return ret;
}
//合并同类项并排序
void Merge() {
//临时向量vt
vector<Mo> vt;
for(auto &vi:v) {
//遍历现有的每个项,在临时向量中找它已经插入的同类项,若找到可以合并的项,系数相加
int suc=0;
for(auto &vti:vt) {
if(vti.canMerge(vi)) {
vti.xs+=vi.xs;
suc=1;
break;
}
}
if(suc==0) {
//没有同类项,则接在临时向量的后面
vt.push_back(vi);
}
}
v.clear();
//清空原向量
for(auto vti:vt) {
//遍历临时向量,去除系数为0的项
if(vti.xs) {
v.push_back(vti);
}
}
//排序,按单项式定义的顺序排序
sort(v.begin(),v.end());
}
//返回一整个排序好的多项式,并自动去除最前面的正号
string toString() {
//多项式中没有单项式,返回一个0
if(v.size()==0)
return "0";
Merge(); //合并同类项并排序
string ans="";
for(auto vi:v)
ans+=vi.toString();
//前面已经保证多项式至少有一个单项式,而且它至少会输出一个负号,故可以ans[0]
//去除开头多余的+号
if(ans[0]=='+') {
ans=ans.substr(1,ans.length()-1);
}
return ans;
}
void fromString(string s) {
int n=s.length();
ll xs=0; //带符号系数
ll zs[256]; //带符号指数
memset(zs,0,sizeof(zs));
for(int i=0; i<=n; i++) {
if(i==n) {
//到达字符串结尾,保存最后一个单项式
addMo(xs,zs);
return;
}
if(s[i]=='+'||s[i]=='-'||isdigit(s[i])) {
//遇到数字,处理到直到遇到下一个字母或者运算符或者结尾
//算法的逻辑保证遇到的必定是系数而不是指数
//保存最后一个单项式
addMo(xs,zs);
int flag=1;
if(!isdigit(s[i])) {
//当前遇到的是符号
//cerr<<"+"<<endl;
if(s[i]=='-')
flag=-1;
i++;
//指向符号的下一个字符
if(i==n) {
//到达字符串结尾,保存最后一个单项式?
//符号后面都没有东西,系数是0,不用添加单项式
return;
}
if(isdigit(s[i])) {
//下一个是显式指定的数字,处理到第一个非数字
while(isdigit(s[i])) {
xs=10ll*xs+(s[i]-'0');
i++;
if(i==n) {
//到达字符串结尾,保存最后一个单项式,也就是常数项,当然要注意符号
xs*=flag;
addMo(xs,zs);
return;
}
}
//现在s[i]是非数字,下次for会i++,这里补偿--
i--;
//保存符号
xs*=flag;
} else {
//符号后面不是数字,系数是隐含的1
xs=1;
//现在s[i]是非数字,下次for会i++,这里补偿--
i--;
//保存符号
xs*=flag;
}
} else {
//没有遇到符号就直接遇到数字,是多项式的开头
while(isdigit(s[i])) {
xs=10ll*xs+(s[i]-'0');
i++;
if(i==n) {
//到达字符串结尾,保存最后一个单项式,也就是常数项,当然要注意符号,虽然一定是+1
xs*=flag;
addMo(xs,zs);
return;
}
}
//现在s[i]是非数字,下次for会i++,这里补偿--
i--;
//保存符号,虽然一定是+1
xs*=flag;
}
} else if(isalpha(s[i])) {
//遇到字母,处理到直到遇到下一个字母或者运算符或者结尾
//没有遇到运算符和数字就遇到多项式开头的字母,系数为1
if(xs==0)
xs=1;
//保存这个字母,名字叫做c
int c=s[i];
//cout<<(char)(c)<<"!!!"<<endl;
//指向下一个字符
i++;
if(i==n) {
//到达字符串结尾,保存最后一个单项式
//先把最后一个字符的1次方加上
zs[c]++;
addMo(xs,zs);
return;
}
if(s[i]=='^') {
//是指数符号,说明要继续处理
i++;
//指向下一个数字或者符号
int flag=1;
if(!isdigit(s[i])) {
//当前遇到的是符号
if(s[i]=='-')
flag=-1;
i++;
//指向符号的下一个字符
if(i==n) {
//到达字符串结尾,你符号后面居然没有数?那就认为指数是0吧,舍弃最后一个字母,保存单项式
addMo(xs,zs);
return;
}
ll tzs=0;
if(isdigit(s[i])) {
//下一个是显式指定的数字,处理到第一个非数字
while(isdigit(s[i])) {
tzs=10ll*tzs+(s[i]-'0');
i++;
if(i==n) {
//到达字符串结尾,保存最后一个单项式
//保存最后一个字母的指数,记得乘上符号
zs[c]+=tzs*flag;
addMo(xs,zs);
return;
}
}
//现在s[i]是非数字,下次for会i++,这里补偿--
i--;
//保存符号
tzs*=flag;
//保存指数
zs[c]+=tzs;
} else {
//符号后面不是数字,系数是隐含的1
tzs=1;
//现在s[i]是非数字,下次for会i++,这里补偿--
i--;
//保存符号
tzs*=flag;
//保存指数
zs[c]+=tzs;
}
} else {
//没有遇到符号就直接遇到数字,是正的指数
//cerr<<"...\n"<<endl;
ll tzs=0;
while(isdigit(s[i])) {
tzs=10ll*tzs+(s[i]-'0');
i++;
if(i==n) {
//到达字符串结尾,保存最后一个单项式,也就是常数项,当然要注意符号,虽然一定是+1
tzs*=flag;
zs[c]+=tzs;
addMo(xs,zs);
return;
}
}
//现在s[i]是非数字,下次for会i++,这里补偿--
i--;
//保存符号,虽然一定是+1
tzs*=flag;
//保存指数
zs[c]+=tzs;
}
} else {
//遇到了字母或运算符,保存指数并补偿--
zs[c]++;
i--;
}
}
}
}
//向多项式中添加一个单项式
void addMo(ll &xs,ll *zs) {
if(xs==0)
return;
Mo m;
m.xs=xs;
memcpy(m.zs,zs,sizeof(m.zs));
v.push_back(m);
xs=0;
//不能sizeof(zs),因为这里zs不是数组而只是一个指针
memset(zs,0,sizeof(ll)*256);
}
};
char s[10005],t[10005],n;
int main() {
#ifdef Yinku
freopen("Yinku.in","r",stdin);
#endif // Yinku
fgets(s,10000,stdin);
n=strlen(s);
for(int i=0,j=0; i<=n; i++) {
if(i==n) {
t[j]='\0';
}
if(s[i]!=' '&&s[i]!='\n') {
t[j++]=s[i];
}
}
Poly A;
A.fromString(string(t));
fgets(s,10000,stdin);
n=strlen(s);
for(int i=0,j=0; i<=n; i++) {
if(i==n) {
t[j]='\0';
}
if(s[i]!=' '&&s[i]!='\n') {
t[j++]=s[i];
}
}
Poly B;
B.fromString(string(t));
#ifdef Yinku
cout<<A.toString()<<endl;
cout<<B.toString()<<endl;
#endif // Yinku
Poly C=A+B;
Poly D=A*B;
cout<<C.toString()<<endl;
cout<<D.toString()<<endl;
}
洛谷 - P2281 - 多项式的加法和乘法 - 大模拟的更多相关文章
- 洛谷P1067 多项式输出 NOIP 2009 普及组 第一题
洛谷P1067 多项式输出 NOIP 2009 普及组 第一题 题目描述 一元n次多项式可用如下的表达式表示: 输入输出格式 输入格式 输入共有 2 行 第一行 1 个整数,n,表示一元多项式的次数. ...
- 洛谷1373 小a和uim之大逃离
洛谷1373 小a和uim之大逃离 本题地址:http://www.luogu.org/problem/show?pid=1373 题目背景 小a和uim来到雨林中探险.突然一阵北风吹来,一片乌云从北 ...
- 洛谷 P1373 小a和uim之大逃离
2016-05-30 12:31:59 题目链接: P1373 小a和uim之大逃离 题目大意: 一个N*M的带权矩阵,以任意起点开始向右或者向下走,使得奇数步所得权值和与偶数步所得权值和关于K的余数 ...
- 【题解】洛谷P1373 小a和uim之大逃离(坐标DP)
次元传送门:洛谷P1373 思路 设f[i][j][t][1/0]表示走到(i,j)时 小a减去uim的差值为t 当前是小a取(0) uim取(1) 那么转移就很明显了 f[i][j][t][]=(f ...
- [uoj#34] [洛谷P3803] 多项式乘法(FFT)
新技能--FFT. 可在 \(O(nlogn)\) 时间内完成多项式在系数表达与点值表达之间的转换. 其中最关键的一点便为单位复数根,有神奇的折半性质. 多项式乘法(即为卷积)的常见形式: \[ C_ ...
- 洛谷 P3803 多项式乘法
题目背景 这是一道FFT模板题 题目描述 给定一个n次多项式F(x),和一个m次多项式G(x). 请求出F(x)和G(x)的卷积. 输入输出格式 输入格式: 第一行2个正整数n,m. 接下来一行n+1 ...
- 洛谷 P3803 多项式乘法(FFT) —— FFT
题目:https://www.luogu.org/problemnew/show/P3803 终于学了FFT了! 参考博客:https://www.cnblogs.com/zwfymqz/p/8244 ...
- 模板【洛谷P3811】 【模板】乘法逆元
P3811 [模板]乘法逆元 给定n,p求1~n中所有整数在模p意义下的乘法逆元. T两个点的费马小定理求法: code: #include <iostream> #include < ...
- 洛谷——P1067 多项式输出
P1067 多项式输出 题目描述 一元 n 次多项式可用如下的表达式表示: 其中,aixi称为 i 次项,ai 称为 i 次项的系数.给出一个一元多项式各项的次数和系数,请按照如下规定的格式要求输出该 ...
随机推荐
- CSS常识
1.给一个div设置边框:border:1px #CCCCCC bold; 2.给DOM加小手:cursor:pointer; 取消小手:cursor:auto;
- IOS开发之Iphone和Ipad应用程序图标和启动动画
本文转载至 http://blog.csdn.net/yesjava/article/details/8782060 当我们用xcode开发iphone和ipad应用程序的时候,我们可以用一下表中所显 ...
- 【BZOJ3218】a + b Problem 可持久化线段树优化建图
[BZOJ3218]a + b Problem 题解:思路很简单,直接最小割.S->i,容量为Bi:i->T,容量为Wi:所有符合条件的j->new,容量inf:new->i, ...
- 基于EasyIPCamera实现的数字网络摄像机IPCamera的模拟器IPC RTSP Simulator
还记得去年在北京安博会上,看到一些厂家的展示台上,各种船舶.公路.车辆的高清视频直播,好奇这些数据是怎么接到现场的,现场成百上千家展台,不可能有那么大的带宽供应,细想数据肯定不是实时的,果然,盯着看了 ...
- mac下使用gnu gcc
1 mac下安装gnu gcc brew search gcc brew install gcc@6 2 mac下编写c/c++代码所需的标准库和头文件 2.1 标准c++的库的头文件都是标准化了的, ...
- Delphi的类方法不是静态方法
Delphi中,类方法不是你理解的静态方法 Delphi中的类方法与C++类中的static方法完全没有可比性.Delphi中的类方法是有Self的,而Self就是类本身(注意不是对象),而这个Sel ...
- 搭建iis本地测试服务器
在“开始”选择 “控制面板”,默认是以“类别”显示, 改成“小图标”显示 选择“程序和功能” 进入界面后,点击“启动或关闭Windows功能” 然后勾选图中的两个选框,注意一定要显示为 ...
- http://www.cnblogs.com/yaozhenfa/archive/2015/06/14/4574898.html
笔者这里采用的是mongoDB官网推荐使用.net驱动: http://mongodb.github.io/mongo-csharp-driver/2.0/getting_started/quick_ ...
- Fast RCNN中RoI的映射关系
写在前面:下面讨论中Kernel Size为奇数,因为这样才能方便一致的确认Kernel中心. 在Fast RCNN中,为了大大减少计算量,没有进行2k次运算前向运算,而是进行了1次运算,然后在从po ...
- BZOJ_2369_区间_决策单调性
BZOJ_2369_区间_决策单调性 Description 对于一个区间集合 {A1,A2……Ak}(K>1,Ai不等于Aj(i不等于J),定义其权值 S=|A1∪A2∪……AK|*|A1 ...