洛谷 题解 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);
}
}

浙公网安备 33010602011771号