P4711 题解
DWT8125
·
·
题解
【淼】+评价
这道题对本蒟蒻来说比较特别,因为这是本人\color{green}\ {AC} 的第一道绿题!
这是一道比较有难度的模拟题,据各位题解区的大佬说,这道题曾经是蓝题?!
本题细节较多,接下来会一一详细说明。
题目大意
给出一个化学式,求给定物质的相对分子质量。
化学式格式大家应该都看过了,就不细讲了。题目传送门
普及点
本题使用string类型字符串,会用到以下几种字符串函数:
s.find(a,b):从字符串 s 的第 b 个字符起寻找字符串 a ,找到则返回第一个找到的位置,否则返回 -1 。其中 b 可以省略。
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; //极短主代码,别忘了这行
}
```
制作不易,求通过,求点赞!