P8324 [COCI2021-2022#5] Kemija
题目传送门
思路
题目的要求是判断方程式的配平是否正确,我们可以根据化学中的原子守恒定律,即方程式两端的每个原子的个数相同,所以,就可以很轻松的得出本题的算法——
我们可以读入一个字符串,便利过去,在箭头之前就把每个大写字母的数量进行统计,在箭头之后就减去每个大写字母出现的个数,最后判断一下是否每个统计的大写字母出现的次数是否为零,如果是就输出 DA 不然就输出 NE 。
同时关于方程式前和方程式中的字符处理,方程式前的可以参考(读出多位数各个数位上的数的方法),即可利用 \(\text{flag}\) 来储存数字,遇到加号就将 \(\text{flag}\) 清零,这里考虑在方程式中会将 \(1\) 隐去,所以这里要特判,在方程式中的就是在大写字母后的数字,只需要在判断每一个大写字母的时候判断一下他的后一位是否是数字就行,如果是数字就乘以 \(\text{flag}\) 使加上的数字变大,但这里要考虑在字符串后加一个字符用来防止越界,这样的话一切都可以迎刃而解了!!!
同时,为了防止出现超过九的数字,我们在记录数字的时候一定要用一个 \(\text{flag}\) 来储存,不然会完蛋。
AC code
代码可能有点长,但是应该是好理解的——
#include<bits/stdc++.h>
using namespace std;
map<char,int> num;//用 map 表示每个大写字母出现的次数
int n,flag,l,x,y;
int main(){
cin>>n;
while(n--){
string s;
cin>>s;
s+='Z';//在最后加上一位,防止出现越界RE
for(char i='A';i<='Z';i++) num[i]=0;
flag=0,l=0;//以上为初始化
for(int i=0;i<s.size()-1;i++){//在箭头的左侧
if(s[i]=='-'){
l=i+2;
break;
}
else if(s[i]>='0' && s[i]<='9') flag=flag*10+s[i]-'0';//对开头数字的处理
else if(s[i]=='+') flag=0;
else if(s[i]>='A' && s[i]<='Z'){
if(s[i+1]>='1' && s[i+1]<='9'){
for(int j=1;j<=s[i+1]-'0';j++){
if(flag==0) num[s[i]]++;
else num[s[i]]+=flag;
}
i++;
}//以上考虑的是多余各个方程式后方的数字
else{
if(flag==0) num[s[i]]++;
else num[s[i]]+=flag;
}
}
}
flag=0;//这里必须要归零,不然会带上上面的数字
for(int i=l;i<s.size()-1;i++){//在箭头的右侧
if(s[i]>='0' && s[i]<='9') flag=flag*10+s[i]-'0';
else if(s[i]=='+') flag=0;
else if(s[i]>='A' && s[i]<='Z'){
if(s[i+1]>='1' && s[i+1]<='9'){
for(int j=1;j<=s[i+1]-'0';j++)
if(flag==0) num[s[i]]--;
else num[s[i]]-=flag;
i++;
}
else{
if(flag==0) num[s[i]]--;
else num[s[i]]-=flag;
}//皆同上
}
}
flag=0;//这里的 flag 表示有无差别
for(char i='A';i<='Z';i++){
if(num[i]!=0) flag=1;
}//如果有差别就 flag 为1
if(flag) cout<<"NE"<<endl;
else cout<<"DA"<<endl;
}
return 0;
}

浙公网安备 33010602011771号