1. 题目

传送门= ̄ω ̄=

2. 题解

首先解析方程式,利用化学式最多是两个字符,根据大写字母判断一个新的元素。

读到左括号,就暴力找到右括号。显然不会有两重括号嵌套(除非出题人 sb)。然后获取括号的系数。

对于字符串,你可以去 map,当然其实因为最长为 2,直接字符串转整数哈希就行了。

最后跑高斯消元。

无解的情况是最后一项的系数消完还是不等于 0。

需要枚举最后一项的值。我是从 1 枚举到一千。

注意消元可能会得到负数解,要舍去。

至于氧化还原反应需要支持归中不交叉率,直接打表好了。

代码:

#include <bits/stdc++.h>
using namespace std;
int n,m,sum,h[3000],hs;
double g[3000][205],ans[205];
string str[205];
bool book[3000];
int sti(string s)
{
    if(s.length()==1)return s[0]-'A'+1;return (s[0]-'A'+1)*100+s[1]-'a'+1;
}
void work(int f,int k)
{
    string a,b;cin>>a,str[f]=a;
    int cnt,buf=1;
    for(int i=0;i<a.length();i++)
        if(isupper(a[i]))
        {
            cnt=0,b.clear(),b.push_back(a[i]);
            for(++i;i<a.length();i++)if(islower(a[i]))b.push_back(a[i]);else break;
            for(;i<a.length();i++)if(isdigit(a[i]))cnt=cnt*10+a[i]-'0';else break;
            if(!cnt)cnt=1;
            i--,g[sti(b)][f]+=cnt*buf*k;
            if(!book[sti(b)])h[hs++]=sti(b),book[sti(b)]=1;
        }
        else if(a[i]=='(')
        {
            int j=i;buf=0;
            for(;a[j]!=')';j++);
            for(++j;j<a.length();j++)if(isdigit(a[j]))buf=buf*10+a[j]-'0';else break;
        }
}
int main()
{
    scanf("%d%d",&n,&m),sum=n+m;
    for(int i=0;i<n;i++)work(i,1);
    for(int i=0;i<m;i++)work(i+n,-1);
    for(int i=0;i<sum;i++)
    {
        for(int j=i+1;j<hs;j++)if(abs(g[h[i]][i])<abs(g[h[j]][i]))swap(h[i],h[j]);
        if(abs(g[h[i]][i])<1e-8)continue;
        for(int j=sum-1;j>=i;j--)g[h[i]][j]/=g[h[i]][i];
        for(int j=i+1;j<hs;j++)
            for(int k=sum-1;k>=i;k--)
                g[h[j]][k]-=g[h[i]][k]*g[h[j]][i];
    }
    if(abs(g[h[sum-1]][sum-1])>1e-8)goto end;
    for(ans[sum-1]=1;ans[sum-1]<=1000;ans[sum-1]+=1)
    {
        for(int i=sum-2;i>=0;i--)
        {
            if(abs(g[h[i]][i])<1e-8)
                {printf("3H2S+K2Cr2O7+4H2SO4=Cr2(SO4)3+K2SO4+3S+7H2O\n");return 0;}
            ans[i]=0;
            for(int j=i+1;j<sum;j++)ans[i]-=ans[j]*g[h[i]][j];
            if(abs(ans[i]-round(ans[i]))>1e-8||ans[i]<0)goto again;
        }
        for(int i=0;i<n;i++)
        {
            if(ans[i]>1+1e-8)cout<<ans[i];cout<<str[i];
            if(i!=n-1)cout<<'+';
        }cout<<'=';
        for(int i=n;i<sum;i++)
        {
            if(ans[i]>1+1e-8)cout<<ans[i];cout<<str[i];
            if(i!=sum-1)cout<<'+';
        }
        cout<<endl;return 0;again:;
    }
    end:printf("Error\n");return 0;
}
分类: 文章

XZYQvQ

炒鸡辣鸡的制杖蒟蒻一枚QvQ

1 条评论

boshi · 2017年6月23日 5:10 下午

%%% 太强了%%% 我一用 map 和分数表示法就300行

发表回复

Avatar placeholder

您的电子邮箱地址不会被公开。 必填项已用*标注