这道题是裸的高斯消元,设每种物质前面的化学计量数是xi,写方程出来解就可以了
有几个注意点:
1.化学计量数的方程一定是一个不定方程组,为了保证方程组有唯一解,加一个x1=1
2.化学计量数一定要是整数,所以要用分数来表示方程的解,最后通分
为了防止通分时最小公分母过大,最好开long long
3.可以用递归风骚的处理字符串
贴代码
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <cstdlib>
#include <utility>
#include <map>
#include <stack>
#include <set>
#include <vector>
#include <queue>
#include <deque>
#include <sstream>
#define x first
#define y second
#define mp make_pair
#define pb push_back
#define LL long long
#define LOWBIT(x) x & (-x)
using namespace std;
const int MOD=1e9+7;
const int INF=0x7ffffff;
const int magic=348;
typedef pair<LL,LL> Pair;
int ll,rr;
int n=0,m;
LL b[48][48];
map<string,LL> ID;
map<LL,LL>::iterator iter;
Pair sol[48];
LL res[48];
inline LL gcd(LL x,LL y)
{
if (y==0) return x; else return gcd(y,x%y);
}
inline LL lcm(LL x,LL y)
{
LL res=gcd(x,y);
return x/res*y;
}
inline LL myabs(LL x)
{
return x>=0?x:-x;
}
inline void clear(int x)
{
for (int i=1;i<=m;i++) b[x][i]=0;
}
inline LL getID(string el)
{
if (ID[el]) return ID[el];
ID[el]=++n;clear(n);
return n;
}
LL readcoef(string &s)
{
if (!isdigit(s[0])) return 1;
int len=1;LL res;
while (len<=s.size() && isdigit(s[len])) len++;
stringstream ss(s.substr(0,len));
s.erase(0,len);
ss>>res;
return res;
}
void doit(string &s,map<LL,LL> &M)
{
if (s.size()==0) return;
if (isupper(s[0]))
{
int len=1;
while (islower(s[len]) && len<=s.size()-1) len++;
string el=s.substr(0,len);s.erase(0,len);
LL num=getID(el);
M[num]+=readcoef(s);
doit(s,M);
}
if (s[0]=='(')
{
s.erase(0,1);
map<LL,LL> tmp;doit(s,tmp);
s.erase(0,1);
LL coef=readcoef(s);
for (iter=tmp.begin();iter!=tmp.end();iter++) M[iter->first]+=iter->second*coef;
doit(s,M);
}
}
inline void swap(int r1,int r2)
{
for (int i=1;i<=m;i++) swap(b[r1][i],b[r2][i]);
}
inline void remove(int r1,int r2,int col)
{
if (b[r2][col]==0) return;
LL lc=lcm(myabs(b[r1][col]),myabs(b[r2][col]));
LL lr1=lc/b[r1][col],lr2=lc/b[r2][col];
for (int i=col;i<=m;i++) b[r2][i]=lr2*b[r2][i]-lr1*b[r1][i];
}
Pair frac(LL x,LL y)
{
LL g=gcd(myabs(x),myabs(y));
x/=g;y/=g;
if (y<0)
{
x=-x;
y=-y;
}
return mp(x,y);
}
bool solve()
{
int i,j,rr;
for (j=1;j<=m-1;j++)
{
rr=j;
while (rr<=n && b[rr][j]==0) rr++;
if (rr==n+1) return false;
if (rr!=j) swap(j,rr);
for (i=rr+1;i<=n;i++) remove(j,i,j);
}
for (i=m;i<=n;i++) if (b[i][m]!=0) return false;
sol[m-1]=frac(b[m-1][m],b[m-1][m-1]);
if (sol[m-1].x<=0) return false;
for (i=m-2;i>=1;i--)
{
LL lc=1,val;
for (j=i+1;j<=m-1;j++)
lc=lcm(lc,sol[j].y/gcd(sol[j].y,myabs(b[i][j])));
for (j=i;j<=m;j++) b[i][j]*=lc;
val=b[i][m];
for (j=m-1;j>=i+1;j--) val-=b[i][j]/sol[j].y*sol[j].x;
sol[i]=frac(val,b[i][i]);
if (sol[i].x<=0) return false;
}
LL lc=1;
for (i=1;i<=m-1;i++) lc=lcm(lc,sol[i].y);
for (i=1;i<=m-1;i++) res[i]=sol[i].x*lc/sol[i].y;
return true;
}
int main ()
{
int i,j,mul,tot=0;
string s;
while (scanf("%d%d",&ll,&rr)==2 && ll && rr)
{
m=ll+rr+1;
memset(b,0,sizeof(b));
n=0;ID.clear();
for (i=1;i<=m-1;i++)
{
cin>>s;
map<LL,LL> M;
doit(s,M);
mul=i<=ll?1:-1;
for (j=1;j<=n;j++) b[j][i]=mul*M[j];
}
clear(++n);b[n][1]=1;b[n][m]=1;
printf("Case %d: ",++tot);
if (!solve())
{
printf("No\n");
continue;
}
for (i=1;i<=ll+rr;i++) printf("%d ",res[i]);
printf("\n");
}
return 0;
}