Loading

洛谷 题解 P1557 【Kruscal的加法】

题目链接

首先,数据范围是长度不超过2000,所以要开高精度

根据题意,有加法,减法和乘法。所以先把高精度写完(我使用的是vector)。

加法高精度

vector<int> Plus(const vector<int>& a,const vector<int>& b)
{
	vector<int>c(max(a.size(),b.size())+1);
	for (int i=0;i<min(a.size(),b.size());++i)
		c[i]+=a[i]+b[i];
	if (a.size()>b.size())
	for (int i=b.size();i<a.size();++i)c[i]=a[i];
	else for (int i=a.size();i<b.size();++i)c[i]=b[i];
	for (int i=0;i<c.size()-1;++i)
	{
		c[i+1]+=c[i]/10;
		c[i]%=10;
	}
	if (!c[c.size()-1])c.pop_back(); //最高位为0
	return c;
}

减法高精度

vector<int> Minus(vector<int> a,vector<int> b) //a-b
{
	int cmpans=cmp(a,b); //这是比较两个数大小
	if (!cmpans) //相等的情况
	{
		vector<int>c;
		c.push_back(0);
		return c;
	}
	else if(cmpans==-1) //a<b
	{
		neg=!neg; //这是一个标签,记录是不是负数
		swap(a,b);
	}
	vector<int>c(max(a.size(),b.size()));
	for (int i=0;i<min(a.size(),b.size());++i)
		c[i]=a[i]-b[i];
	for (int i=b.size();i<a.size();++i)c[i]=a[i];
	for (int i=0;i<c.size()-1;++i)
	{
		if (c[i]<0)
		{
			--c[i+1];
			c[i]+=10;
		}
	}
	while (!c[c.size()-1])c.pop_back(); //最高位为0
	return c;	
}

乘法高精度

vector<int> mul(const vector<int>&a,const vector<int>&b)
{
	vector<int>c(a.size()+b.size());
	for (int i=0;i<a.size()+b.size();++i)c[i]=0;
	for (int x=0;x<a.size();++x)
	for (int y=0;y<b.size();++y)
	{
		c[x+y]+=a[x]*b[y]; //想想为什么
	}
	for (int i=0;i<c.size()-1;++i)
	{
		c[i+1]+=c[i]/10;
		c[i]%=10;
	}
	if (!c[c.size()-1])c.pop_back(); //最高位为0
	return c;
}

接下是字符串处理。

方法:将整个字符串拆成表达式,每个表达式单独计算,最后加到ans里。

有以下几种情况:

\(+++x\)

计算有多少个加号,再读入数字,把他们乘起来。

charge(to,bit-i/*加号个数*/); //把to填充为加号个数
while (isdigit(s[i]))num.push_back(s[i]-'0'),++i;
reverse(num.begin(),num.end()); //因为读入是反着的,要把高低位反过来
num=mul(num,to); //乘起来
--i; //因为更新时会跳过一个字符,所以要后退一个

\(+(x)x\)

分别读入括号里的数和后面的数,再乘起来。

++i; //跳过加号
while (s[i]!=')')to.push_back(s[i]-'0'),++i;
reverse(to.begin(),to.end());
++i; //跳过右括号
while (isdigit(s[i]))num.push_back(s[i]-'0'),++i;
reverse(num.begin(),num.end());
num=mul(num,to);
--i;

\(+x\)

同多个加号(为什么一个加号要单独处理

while (isdigit(s[i]))num.push_back(s[i]-'0'),++i;
reverse(num.begin(),num.end());
--i;

\(x\)

只有第一个表达式才会出现。(very easy)

while (isdigit(s[i]))num.push_back(s[i]-'0'),++i;
reverse(num.begin(),num.end());
--i;

余下三种:

\(---x\)

\(-(x)x\)

\(-x\)

同加法(太长不贴了)


终极问题:

Q:如何把表达式加到ans里面?

A:字符串处理+分类讨论。

(r函数表示参数为(num,ans))

ans符号 num符号 处理方法
+ + Plus
+ - Minus(高精度已做正负处理)
- + rMinus,ans取相反数
- - Plus
ans.push_back(0); //答案初始化为0
vector<int>num,to; //num是要加(减)的数,to是有多少个num相加(减)
for (int i=0;i<s.size();++i)
{
	num.clear();
	to.clear(); //初始化
	if (s[i]=='+') //加减法分开讨论
	{
		int bit=i;
		for (;s[i]=='+';++i); //记录有多少个加号
		//bit-i为加号个数
       		/*省略num处理过程(上面有)*/
               	//重点
		if (neg) ans=Minus(num,ans),neg=!neg; //判断ans是否为负,分开处理
		else ans=Plus(ans,num);
	}
	else if (s[i]=='-') //原理同加
	{
		//处理过程同加法,省去
		if (neg)ans=Plus(ans,num);
		else ans=Minus(ans,num);
	}
}
posted @ 2021-01-10 22:34  NFLS  阅读(190)  评论(0)    收藏  举报