题解 P4711 【「化学」相对分子质量】

引领天下

2018-06-24 21:55:01

Solution

恩这题其实并没有那么难,根本没有必要搞什么单调栈什么的,所以我来一发很短的题解。 本题的思路就是逐个击破,我的思路是这样的: # 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; } ```