1 条题解
-
0
自动搬运
来自洛谷,原作者为

虞皓翔
Eternal dominant seventh.搬运于
2025-08-24 21:39:58,当前版本为作者最后更新于2017-06-26 10:41:14,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
这道题嘛,肯定不用从化学的角度思考(神马乱凑啊,奇偶分析啦,化合价分析啦等等都可能过不去)。
如果你看到一个不会配平的方程式,如果你不想思考,你的第一反应一定是:待定系数法。
“待定系数法”什么意思?就是把它们都设出来,再解方程,那么你一定会想到——高斯消元。
举个例子(样例):
我们设一下系数:
根据元素守恒,我们就得到了一个线性方程组:
显然,它有4个未知数,却只有3个方程,这是无法解的。
但你要发现,化学方程式的特点,如果去掉最大公因数为1和整数的条件,如果把每种物质的系数乘上(除以)同一个数后,它依旧是配平的,所以我们可以假设一个值为1,根据个人习惯,我假设。
那么方程变成了:
解之,得
因此,原来的方程式为
我们只需要取分母的最小公倍数 (本例中为9),就得到正确的方程式:
所以,本题的基本思路就是一开始写一大堆字符串处理,然后开始高斯消元。
未知数的个数 等于物质的种类数,方程的个数 为元素的个数,数据一定会保证 ,因为我们总是可以假设一个数为1。
如果 ,如果我们加上绝对值优化的话,数据一定会保证最后 行为全0,所以只需处理前 个数即可。
长(chou)的要死的代码:
(分数类和高斯消元)
typedef long long ll; struct frac{ ll x, y; frac (ll x0 = 0, ll y0 = 1): x(x0), y(y0) { if(!y0) y0 = 1; Canonicity(); } void Canonicity(){ if(y < 0){ x = -x; y = -y; } ll d = gcd(abs(x), y); x /= d; y /= d; } frac operator + (const frac &b) const {return frac(x * b.y + y * b.x, y * b.y);} frac operator - (const frac &b) const {return frac(x * b.y - y * b.x, y * b.y);} frac operator * (const frac &b) const {return frac(x * b.x, y * b.y);} frac operator / (const frac &b) const {return frac(x * b.y, y * b.x);} bool operator < (const frac &b) const {return x * b.y < y * b.x;} bool operator > (const frac &b) const {return b < *this;} bool operator == (const frac &b) const {return x * b.y == y * b.x;} bool operator != (const frac &b) const {return !(*this == b);} void print(){ if(y == 1) printf("%lld", x); else printf("%lld/%lld", x, y); } }; inline frac frabs(frac z){ if(z.x < 0) z.x = -z.x; return z; } template <typename T> struct LnEqn{ int r, c; T **m, *b; LnEqn (){m = NULL; b = NULL;} void resize(int r0, int c0){ r = r0; c = c0; m = new T *[r]; for(int i = 0; i < r; i++){ m[i] = new T[c]; memset(m[i], 0, c * sizeof(T)); } b = new T[r]; memset(b, 0, r * sizeof(T)); } ~LnEqn (){ if(m != NULL){for(int i = 0; i < r; i++) delete [] (m[i]); delete [] (m);} if(b != NULL) delete [] (b); } bool solve(){ int i, j, k, maxi; T coe; for(k = 0; k < c; k++){ maxi = k; for(i = k + 1; i < r; i++) if(frabs(m[i][k]) > frabs(m[maxi][k])) maxi = i; if(frabs(m[maxi][k]) == frac(0)) return false; if(maxi != k){ swap(m[maxi], m[k]); swap(b[maxi], b[k]); } coe = m[k][k]; for(j = 0; j < c; j++) m[k][j] = m[k][j] / coe; b[k] = b[k] / coe; for(i = 0; i < r; i++){ if((i == k ? ++i : i) >= r) break; coe = m[i][k]; for(j = 0; j < c; j++) m[i][j] = m[i][j] - coe * m[k][j]; b[i] = b[i] - coe * b[k]; } } return true; } };(字符串处理)
//nextint函数定义 int nextint(char *p, char **q){ if(!isdigit(*p)){ if(q != NULL) *q = p; return 1; } int b; for(b = *p - 48; isdigit(*++p); b = b * 10 + (*p - 48)); if(q != NULL) *q = --p; return b; } //主字符串处理,适当的应用scanf技巧 for(n = 0; ; ++n){ scanf("%[^ +=\n]", s[n]); // reading matter for(p = s[n]; *p; ++p){ if(*p == '('){ for(q = p; *q != ')'; ++q); Mul = nextint(++q, NULL); }else if(*p == ')'){ nextint(++p, &p); Mul = 1; }else if(*p >= 'A' && *p <= 'Z'){ elem = *p - 65; if(p[1] >= 'a' && p[1] <= 'z'){ elem = elem * 26 + (p[1] - 65); ++p; } mul = 1; if(isdigit(p[1])) mul = nextint(++p, &p); eid = (~idx[elem] ? idx[elem] : idx[elem] = nid++); coe[eid][n] += Mul * mul; //printf("elem = %d, coe[%d][%d] = %d\n", elem, eid, n, coe[eid][n]); } } scanf("%[ +=\n]", s[N - 1]); // reading signs for(p = s[N - 1]; *p; ++p){ if(*p == '=') eq = n + 1; if(*p <= '\n') break; } if(*p && *p <= '\n'){++n; break;} }
- 1
信息
- ID
- 1688
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者