P4711 题解

· · 题解

【淼】+评价

这道题对本蒟蒻来说比较特别,因为这是本人\color{green}\ {AC}第一道绿题

这是一道比较有难度的模拟题,据各位题解区的大佬说,这道题曾经是蓝题?!

本题细节较多,接下来会一一详细说明。

题目大意

给出一个化学式,求给定物质的相对分子质量。

化学式格式大家应该都看过了,就不细讲了。题目传送门

普及点

本题使用string类型字符串,会用到以下几种字符串函数:

  1. s.find(a,b):从字符串 s 的第 b 个字符起寻找字符串 a ,找到则返回第一个找到的位置,否则返回 -1 。其中 b 可以省略。
  2. s.substr(a,b):截取从 s 字符串中的第 a 个字符起的 b 个字符。

思路

本人的思路:

double read(string a){
    double s=0,t=0; //s存放总质量,t存放目前待处理的元素

1. 准备工作

先对着附表打两个表,一个存元素,一个存对应质量(要用double类型),下标对齐(也可以用结构体):

const string y[]={" ","H","C","N","O","F","Na","Mg","Al","Si","P","S","Cl","K","Ca","Mn","Fe","Cu","Zn","Ag","I","Ba","Hf","Pt","Au","Hg"};
const double no[]={0,1,12,14,16,19,23,24,27,28,31,32,35.5,39,40,55,56,64,65,108,127,137,178.5,195,197,201};
//打表(本人喜欢从下标1存起) 

接着写比较函数,string类型的好处来了:可以像数字一样直接比较!

double fi(string a){
    for(int i=1;i<=25;i++)
        if(y[i]==a) //string的好处:可以直接比较 
            return no[i];  
    return -1;
} //寻找对应的分子质量 

2.处理字符串

``` for(int i=0;i<a.size();i++){ //处理 } ``` 字符串中的字符有几种要重点注意: 1. ```'('```:要截出括号内的内容,可以用```a.find()```和```a.substr()```嵌套: ```cpp if(a[i]=='(') t=read(a.substr(i+1,a.find(')')-i)),i=a.find(')')+1; //这里把后面的')'也截了进去,对应下方的判断 else if(a[i]==')') return s; ``` 1. ```'_'```:遇到这个字符时不能直接加,后面还跟着元素数量,此时就可以用快读思想读入数量,再调用**待处理的元素质量** $t$ 乘上数量: ```cpp if(a[i]=='_'){ double s2=0; for(i+=2;a[i]>='0'&&a[i]<='9';i++) //i+=2 跳过'_'和'{' s2=s2*10+(a[i]-'0'); s+=t*s2; } ``` 1. ```'~'```:字符串的结尾,后面跟数量和```H_{2}O```。既然```H_{2}O=18```,我们可以直接用 $s2 \times 18$ 即可,其中 $s2$ 是数量。 **重点**:水之前如果存在数字,保证一定是大于 2 的正整数,**如果省略该部分则默认为 1**。 ```cpp if(a[i]=='~'){ double s2=0; if(a[i+1]=='H') return 18+s; //不加的话 #12 会错 for(i+=1;a[i]>='0'&&a[i]<='9';i++) s2=s2*10+(a[i]-'0'); s+=s2*18; return s; } ``` ## AC代码 为了您不被棕,请不要抄袭代码! ```cpp //P4711 AC代码 #include<bits/stdc++.h> using namespace std; //万能开头 const string y[]={" ","H","C","N","O","F","Na","Mg","Al","Si","P","S","Cl","K","Ca","Mn","Fe","Cu","Zn","Ag","I","Ba","Hf","Pt","Au","Hg"}; const double no[]={0,1,12,14,16,19,23,24,27,28,31,32,35.5,39,40,55,56,64,65,108,127,137,178.5,195,197,201}; //打表 double fi(string a){ for(int i=1;i<=25;i++) if(y[i]==a) //string的好处:可以直接比较 return no[i]; return -1; } //寻找对应的分子质量 double read(string a){ //核心 double s=0,t=0; //s存放总质量,t存放目前待处理的元素 for(int i=0;i<a.size();i++){ if(a[i]>='A'&&a[i]<='Z'){ //找到一个元素 if(a[i+1]>='a'&&a[i+1]<='z'&&i<a.size()-1){ //判断元素长度+防越界操作 if(!(a[i-1]>='A'&&a[i-1]<='Z'||(a[i-1]>='a'&&a[i-1]<='z')||a[i-1]=='}')) s+=t; //杜绝重复计算!! t=fi(a.substr(i,2)); //截2个字符 } else{ t=fi(a.substr(i,1)); //一个字符就够了 if(a[i+1]!='_') s+=t; } } else if(a[i]>='a'&&a[i]<='z'&&a[i+1]!='_') s+=t; else if(a[i]=='(') t=read(a.substr(i+1,a.find(')')-i)),i=a.find(')')+1; //i变了,所以下方的 if(a[i]=='_') 不加else else if(a[i]==')') return s; if(a[i]=='_'){ double s2=0; for(i+=2;a[i]>='0'&&a[i]<='9';i++) s2=s2*10+(a[i]-'0'); s+=t*s2; } else if(a[i]=='~'){ double s2=0; if(a[i+1]=='H') return 18+s; //不加的话 #12 会错 for(i+=1;a[i]>='0'&&a[i]<='9';i++) s2=s2*10+(a[i]-'0'); s+=s2*18; return s; } } return s; //千万别忘加了! } int main(){ string a; cin>>a; cout<<read(a); return 0; //极短主代码,别忘了这行 } ``` 制作不易,求通过,求点赞!