题解 炼金术士的疑惑
考场上把这题恶心的读入写完,把高斯消元的板子打完,觉得未知数大于方程个数没法解就没交……
事实上直接交上去有75pts,血亏
- 其实高斯消元有个性质:即使出现不合法情况,其解出的结果也一定是一组合法解。这个性质用在类似这题可以骗到不少分,
因为这题数据保证有解,所以解出来每种元素的焓可能是错的,但对它们按系数比求和一般是对的
其实这题是高斯消元的另一种神奇用法,把要求解的方程一起带进去加减消元即可 - 开题分四步:算空间,看输入格式/范围,查精度,手模一组样例验证题意
- 剩的时间不多了一定要静态查错,尤其是状态不太好的时候,容易打错各种细节
这题其实是高斯消元一个神奇的情况:我们求不出每个未知数具体的值,但我们能用它表示出答案
记个性质吧……考场上还真想不到能这么搞
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 230
#define ll long long
#define ld long double
#define usd unsigned
#define ull unsigned long long
//#define int long long
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, tot;
map<string, int> mp;
string s, t;
double ans[N];
const double eps=1e-10;
struct matrix{
int n, m;
double a[N][N];
void resize(int i, int j) {n=i; m=j;}
inline double* operator [] (int i) {return a[i];}
void put() {for (int i=1; i<=n; ++i) {for (int j=1; j<=m; ++j) cout<<a[i][j]<<' '; cout<<endl;}}
void gauss() {
for (int i=1; i<=n; ++i) {
int r=i;
for (int j=i+1; j<=n; ++j) if (fabs(a[j][i])>fabs(a[r][i])) r=j;
if (i!=r) swap(a[i], a[r]);
for (int j=1; j<=n; ++j) {
if (i==j) continue;
if (fabs(a[i][i])<eps) continue;
double d=a[j][i]/a[i][i];
for (int k=1; k<=m; ++k) a[j][k] -= a[i][k]*d;
}
if (fabs(a[n+1][i])>eps) {
double d=a[n+1][i]/a[i][i];
for (int k=1; k<=m; ++k) a[n+1][k] -= a[i][k]*d;
}
}
for (int i=1; i<=n; ++i) ans[i]=a[i][m]/a[i][i];
//for (int i=1; i<=n; ++i) cout<<ans[i]<<' '; cout<<endl;
}
}mat;
inline double tran() {
//cout<<"tran "<<s<<endl;
double ans=0, f=1, e=0.1, len=s.length(), pos=0;
char c=s[pos++];
while (!isdigit(c)) {if (c=='-') f=-f; c=s[pos++];}
while (pos<=len) {if (c=='.') break; ans=ans*10+(c^48); c=s[pos++];}
//cout<<"ans: "<<ans<<endl;
if (c=='.') {
c=s[pos++];
//cout<<"c: "<<c<<endl;
while (pos<=len) {ans+=e*(c^48); e/=10; c=s[pos++];}
}
//cout<<"return "<<ans*f<<endl;
return ans*f;
}
signed main()
{
#ifdef DEBUG
freopen("1.in", "r", stdin);
#endif
double h, ans2=0;
n=read();
mat.resize(n, 205);
for (int i=1; i<=n; ++i) {
while (1) {
cin>>s;
if (isdigit(s[0])) {
h=tran();
cin>>s;
if (!mp[s]) mp[s]=++tot;
//cout<<mp[s]<<endl;
mat[i][mp[s]]=h;
//cout<<t2<<endl;
}
else if (s[0]=='=') break;
}
while (1) {
cin>>s;
if (isdigit(s[0])) {
h=tran();
cin>>s;
if (!mp[s]) mp[s]=++tot;
mat[i][mp[s]]=-h;
//cout<<-t2<<endl;
}
else if (s[0]=='H') break;
}
cin>>h;
mat[i][205]=h;
//cout<<h<<endl;
}
while (1) {
cin>>s;
if (isdigit(s[0])) {
h=tran();
cin>>s;
mat[n+1][mp[s]]=h;
}
else if (s[0]=='=') break;
}
while (1) {
cin>>s;
if (isdigit(s[0])) {
h=tran();
cin>>s;
mat[n+1][mp[s]]=-h;
}
else if (s[0]=='H') break;
}
//mat.put(); cout<<endl;
mat.gauss();
//mat.put(); cout<<endl;
printf("%.1lf\n", -mat[n+1][205]+eps);
return 0;
}