题解 P4711 【「化学」相对分子质量】
引领天下
2018-06-24 21:55:01
恩这题其实并没有那么难,根本没有必要搞什么单调栈什么的,所以我来一发很短的题解。
本题的思路就是逐个击破,我的思路是这样的:
# 1.元素
对于单个元素的处理应该是很简单的,因为我们有强大的map,一个表就结束了。
# 2.下标
这里我主要分两种情况看:
- 对原子的下标
只需要保存每个元素的值(last),如果发现下标就把已经加到ans里的last减掉,重新加上last×下标系数就可以了。
- 对原子团的下标
这个等会会在原子团的部分里解释
# 3.原子团
这个对于原子团中可能出现的**嵌套**问题,我选择了递归解决
原子团中的原子跟原子团外的原子是一个解决方法(原子+下标)
然后接下来就是**原子团的下标**了
这个问题需要我们对原子团中的运算结果进行一个tmp的保存,然后在退出函数之前检查外面有没有下标,有的话立即解决。
# 4.水合物
这个就很简单了,检测到~后直接计算系数,然后乘以18(H_{2}O的值)就可以了
具体的一些坑点会在代码里说
```cpp
#include <bits/stdc++.h>
using namespace std;
double ans,last;//小心别手残打成int了(因为有.5的存在)
string a;
map <string,double> mp;//一个map其实可以帮我们很多忙
inline void start(){mp["H"]=1;
mp["C"]=12;
mp["N"]=14;
mp["O"]=16;
mp["F"]=19;
mp["Na"]=23;
mp["Mg"]=24;
mp["Al"]=27;
mp["Si"]=28;
mp["P"]=31;
mp["S"]=32;
mp["Cl"]=35.5;
mp["K"]=39;
mp["Ca"]=40;
mp["Mn"]=55;
mp["Fe"]=56;
mp["Cu"]=64;
mp["Zn"]=65;
mp["Ag"]=108;
mp["I"]=127;
mp["Ba"]=137;
mp["Hf"]=178.5;
mp["Pt"]=195;
mp["Au"]=197;
mp["Hg"]=201;}//打表
int ys(int k){
string s="";int j=k+1;s+=a[k];
for (;a[j]>='a'&&a[j]<='z';j++)s+=a[j];
ans+=last=mp[s];//存下上一个值,为下标作准备
return j;
}//对单个元素处理:用string提取单个元素,然后直接拿mp映射表搞
int xb(int k){
int j=k+2,s=0;
for (;a[j]>='0'&&a[j]<='9';j++)s=s*10+a[j]-'0';
ans-=last,ans+=last*s;
return j;
}//外部下标
double tmp,tlast;//tmp为括号里的运算结果,tlast为括号里的上一个值
int xbk(int k){
int j=k+2,s=0;
for (;a[j]>='0'&&a[j]<='9';j++)s=s*10+a[j]-'0';
tmp-=tlast,tmp+=tlast*s;
return j;
}//括号里的下标
int ysk(int k){
string s="";int j=k+1;s+=a[k];
for (;a[j]>='a'&&a[j]<='z';j++)s+=a[j];
tmp+=tlast=mp[s];
return j;
}//括号里的元素
inline int kh(int k){
int j=k+1,h=1;//h表示当前未匹配的左括号数
while (h!=0){
if (a[j]==')')h--;//匹配到一个
if (!h)break;
if (a[j]>='A'&&a[j]<='Z'){
j=ysk(j);
if (a[j]=='_')j=xbk(j)+1;
}else if (a[j]=='(')h++,j=kh(j);//又出来一个,递归
}
if (a[j+1]=='_')ans+=tmp,last=tmp,j=xb(j+1);//原子团的下标
tmp=0;//记得归0
return j;
}//括号
void sh(int k){
int j=k+1,f=0;
for (;a[j]>='0'&&a[j]<='9';j++)f=f*10+a[j]-'0';
if (!f)f++;//注意!!!如果f没提取到说明省略了系数,千万别忘了默认为1!
ans+=f*18;
}//水合物
int main(){
start();
cin>>a;
for (int i=0;i<a.size();i++){
if (a[i]>='A'&&a[i]<='Z')i=ys(i)-1;
else if (a[i]=='_')i=xb(i);
else if (a[i]=='(')i=kh(i);
else if (a[i]=='~'){sh(i);break;}
}
printf ("%g",ans);//%g的输出可以省掉多余的0
return 0;
}
```