题解:「化学」相对分子质量

9773

题解:「化学」相对分子质量

small_lemon_qwq

·

2025-05-29 13:30:31

·

题解

\colorbox{orange}{\color{white}\texttt{题目传送门}}

考虑我们人工计算相对分子质量是怎么算的。

以样例 3 为例,假设我们不知道每个元素的相对元素质量,那么我们可以列出算式:

\operatorname{Mr}(\mathrm{Ca(OH)_2})=\operatorname{Ar}(\mathrm{Ca})+(\operatorname{Ar}(\mathrm{O})+\operatorname{Ar}(\mathrm{H}))\times2

不难发现 \operatorname{Ar}() 不影响我们做题,忽略掉:

\operatorname{Mr}(\mathrm{Ca(OH)_2})=\mathrm{Ca}+(\mathrm{O}+\mathrm{H})\times2

那么我们如果能在程序里实现列出这个算式这个问题就变成了:

将每个元素替换为它对应的相对原子质量

计算表达式值。

步骤 1 显然可以用正则表达式做,表达式:

单元素正则表达式(以 \mathrm{S} 为例):s=regex_replace(s,regex("S([^a-z])"),"127$1"),这里表示将所有 S 加上一个非小写字母字符的子串替换为 127 加上这个非小写字母字符,非小写字母字符是为了防止错误的替换 Si,但是这样就需要再整个字符串后面加入一个特殊字符。

双元素正则表达式(以 \mathrm{Si} 为例):s=regex_replace(s,regex("Si"),to_string(28)),表示将所有 Si 子串替换为 28。

现在的问题就是如何列出这个算式了。

首先忽略掉 ~[数字]H_{2}O,用正则表达式:string s1=regex_replace(s,regex(".*?(~(\\d*?H_\\{2\\}O))?$"),"$2"); 和 string s2=regex_replace(s,regex("(.*?)(~(\\d*?H_\\{2\\}O))?$"),"$1");,其中 s1 表示 ~[数字]H_{2}O 部分,s2 表示除去 ~[数字]H_{2}O 的部分。

接下来观察分子部分。

题目末尾有这样一句话:

下标相当于乘。

直接将下标变为乘号。:string s3=regex_replace(s2,regex("_\\{(\\d*?)\\}"),"*$1");,括号不用处理,只需要处理加号了。

可以直接在每个元素开头加上一个加号,但是对于样例 3 就会变成这样:+Ca(+O+H)*2,所以需要处理一下,在括号前也加入加好,如果一个元素之前没有字符或者是括号就不加入加好。

由于正则表达式不会重复匹配,所以这部分只能手写:

string s4;

char c1='(';

for(char c:s3){

if(c>='A'&&c<='Z'&&c1!='('||c=='('){

s4+="+";

}

s4+=(c1=c);

}

最后就是愉快的表达式计算了,如果用 python 可以用 eval 函数,C++ 就只能手写了。

#include

using namespace std;

#define int long long

#define $(x,y) s4=regex_replace(s4,regex(string(1,x)+"([^a-z])"),to_string((int)(y*2))+"$1")

#define $$(x,y) s4=regex_replace(s4,regex(x),to_string((int)(y*2)))

string s;

mapmp;

int calc(string s){

string b;

stackst;

stackst2;

int x=0;

s="("+s+")";

for(char c:s){

if(c=='('){

st.push('(');

}else if(c=='+'||c=='*'){

if(x)b+=to_string(x)+" ";

x=0;

while(st.size()&&mp[st.top()]>=mp[c]){

b+=st.top()+(string)" ";

st.pop();

}

st.push(c);

}else if(c==')'){

if(x)b+=to_string(x)+" ";

x=0;

while(st.size()&&st.top()!='('){

b+=st.top()+(string)" ";

st.pop();

}

if(st.size())st.pop();

}else if(isdigit(c)){

x=x*10+c-'0';

}

}

x=0;

for(char c:b){

if(isdigit(c)){

x=x*10+c-'0';

}else if(c==' '){

if(x)st2.push(x);

x=0;

}else if((c=='+'||c=='*')&&st2.size()>=2){

int tp2=st2.top();st2.pop();

int tp1=st2.top();st2.pop();

if(c=='+')st2.push(tp1+tp2);

if(c=='*')st2.push(tp1*tp2);

}

}

if(!st2.size())return 0;

return st2.top();

}

signed main(){

ios::sync_with_stdio(0);

cin.tie(0);cout.tie(0);

mp['(']=1;

mp['+']=2;

mp['*']=3;

cin>>s;

string s1=regex_replace(s,regex(".*?(~(\\d*?H_\\{2\\}O))?$"),"$2");

string s2=regex_replace(s,regex("(.*?)(~(\\d*?H_\\{2\\}O))?$"),"$1");

string s3=regex_replace(s2,regex("_\\{(\\d*?)\\}"),"*$1");

// cout<

string s4;

char c1='(';

for(char c:s3){

if(c>='A'&&c<='Z'&&c1!='('||c=='('){

s4+="+";

}

s4+=(c1=c);

}

if(!s1.empty()){

int t=max(stoll(string("0")+regex_replace(s1,regex("(\\d*?)H.+"),"$1")),1ll);

s4+="+"+to_string(t)+"*(H*2+O)";

}

s4+=" ";

$('H',1);

$('C',12);

$('N',14);

$('O',16);

$('F',19);

$$("Na",23);

$$("Mg",24);

$$("Al",27);

$$("Si",28);

$('P',31);

$('S',32);

$$("Cl",35.5);

$('K',39);

$$("Ca",40);

$$("Mn",55);

$$("Fe",56);

$$("Cu",64);

$$("Zn",65);

$$("Ag",108);

$('I',127);

$$("Ba",137);

$$("Hf",178.5);

$$("Pt",195);

$$("Au",197);

$$("Hg",201);

int t=calc(s4);

// cout<

cout<

if(t%2)cout<<".5";

return 0;

}