【题目传送门:】 [戳] (https://www.luogu.org/problemnew/show/P4711)
[算法分析:]
关于一个分子拆分后的产物,一共有三种情况:
原子
原子团
水合物
关于原子的获取可以使用get_ele()函数,由于不是一位的元素就是两位的元素,只要看看这个大写字母的下一位是不是小写字母就行
返回获取的元素的string
关于系数的获取——使用函数get_num()——与快读的写法很接近,当没有系数的时候(处理后系数还是初始值没有被更新),系数是1
如何获取原子团:
在出现左括号的时候使用get_group()函数
使用get_ele()不停地获取括号内的元素直到下一位是系数或者不是元素,
当下一位是系数的时候获取系数,并且获取这一位的元素,将获取的系数与获取的元素相乘。
其他:
相对原子质量是实数,我们可以把他们都乘以10变成整数,有效地防止了被卡精度
在处理水合物的时候记得水的相对分子质量不应是18而是180
使用map来快速地获取每个元素的相对原子质量。
\([Code:]\)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
const int MAXN = 1000 + 1;
map<string, int> m;
string str;
int e, c;
int ele[MAXN], coe[MAXN];
void init() {
m["H"] = 10;
m["C"] = 120;
m["N"] = 140;
m["O"] = 160;
m["F"] = 190;
m["Na"] = 230;
m["Mg"] = 240;
m["Al"] = 270;
m["Si"] = 280;
m["P"] = 310;
m["S"] = 320;
m["Cl"] = 355;
m["K"] = 390;
m["Ca"] = 400;
m["Mn"] = 550;
m["Fe"] = 560;
m["Cu"] = 640;
m["Zn"] = 650;
m["Ag"] = 1080;
m["I"] = 1270;
m["Ba"] = 1370;
m["Hf"] = 1785;
m["Pt"] = 1950;
m["Au"] = 1970;
m["Hg"] = 2010;
}
int get_num(int k) {
int i = k + 2, num = 0;
while(str[i] >= '0' && str[i] <= '9')
num = (num << 3) + (num << 1) + str[i] - '0', ++i;
if(!num) num = 1;
coe[++c] += num;
return i;
}
inline string get_ele(int &k) {
string ret;
ret += str[k];
if(str[k + 1] >= 'a' && str[k + 1] <= 'z')
ret += str[++k];
return ret;
}
int get_group(int k) {
int i = k + 1, num = 0;
while(str[i] >= 'A' && str[i] <= 'Z' && str[i+1] != '_')
num += m[get_ele(i)], ++i;
if(str[i + 1] == '_' && str[i] != ')') {
i = get_num(i + 1);
i -= 4;
num += m[get_ele(i)] * coe[c];
i += 4;
coe[c--] = 0;
}
ele[++e] = num;
return i;
}
int get_h2o(int k) {
int i = k + 1, num = 0;
while(str[i] >= '0' && str[i] <= '9')
num = (num << 3) + (num << 1) + str[i] - '0', ++i;
if(!num) num = 1;
ele[++e] = 180, coe[++c] = num;
return i + 5;
}
int main() {
init();
cin >> str;
int l = str.size();
for(int i=0; i<l; ++i) {
if(str[i] == '_') {
i = get_num(i);
continue;
}
if(str[i] == '(') {
i = get_group(i);
continue;
}
if(str[i] == '~') {
i = get_h2o(i);
continue;
}
if(str[i] >= 'A' && str[i] <= 'Z') {
ele[++e] = m[get_ele(i)];
if(str[i + 1] != '_') coe[++c] = 1;
}
}
int ans = 0;
for(int i=1; i<=e; ++i)
ans += ele[i] * coe[i];
cout << ans / 10.0;
}