[CSP-S模拟测试]:炼金术士的疑惑(模拟+数学+高斯消元)

题目传送门(内部题70)


输入格式

第一行一个正整数$n$,表示炼金术士已知的热化学方程式数量。
接下来$n$行,每行一个炼金术士已知的热化学方程式。
最后一行一个炼金术士想要求解的热化学方程式,末尾记为$H=?$。
每个热化学方程式都是规范的,格式如下:
$a\ W\ +\ b\ X\ +\ ...\ =\ c\ Y\ +\ d\ Z\ ...\ H=\ h$
表示$a$单位的$W$、$b$单位的$X$与......反应生成了$c$单位的$Y$、$d$单位的$Z$和......,吸收$h$/放出$-h$单位热量。
$W\ X\ Y\ Z$为化学物质名称,是一个长度不超过$5$的合法标识符(即首字符是大小写字母,其它字符都是大小写字母或数字)。$a\ b\ c\ d$为各化学物质的系数,是一个小数点后不超过$1$位的$\leqslant 10^2$的正实数。
$h$为反应焓变,是一个小数点后不超过$1$位的、绝对值$\leqslant 10^4$的实数。
$+\ =\ H=$部分均为字符串。$=$左边的物质都是反应物,右边的都是生成物。
任何相邻两个元素间都用一个空格隔开,行末无多余空格。
炼金术士的记忆很好,所以不会存在自相矛盾的情况,他回忆起的方程式也一定能够解出问题的答案。


输出格式

输出一行一个实数,表示解出的热化学方程式的焓变,四舍五入保留$1$位小数。
对于每个测试点,您的输出必须与标准答案完全一致才能得分。


样例

样例输入:

2
1 C + 1 O2 = 1 CO2 H= -393.5
1 CO + 0.5 O2 = 1 CO2 H= -283.0
2 C + 1 O2 = 2 CO H= ?

样例输出:

-221.0


数据范围与提示

数据范围:

设$m$为所有方程式中出现过的化学物质的数量。
对于$20\%$的数据,$n=1,m=2$;
对于$40\%$的数据,$n\leqslant 4,m\leqslant 10$;
对于$70\%$的数据,已知方程式没有重复信息(即不存在任意的若干个已知方程式使得它们经过变换后等于另一个已知方程式);
对于$100\%$的数据,$n,m\leqslant 200$。

下面是可能用到的化学知识,学过高中化学选修$4$第一章的同学们可以跳过了。

热化学方程式:

与一般化学方程式的区别:
  $1.$一般化学方程式的系数必须是最简整数比关系,而热化学方程式没有要求。
  $2.$热化学方程式的末尾有一个位置写明了反应的焓变(热量变化),形如$\Delta H=h$。$h$为正数表示反应吸收了热量,为负数表示放出了$-h$单位的热量。更通俗地来说,设想每种化学物质的单位内能是一定的,那么热化学方程$aW+bX+...=cY+dZ...\Delta H=h$可以这样解释:$a$单位的$W$与$b$单位的$X...$的能量之和,比$c$单位的$Y$与$d$单位的$Z...$的能量之和少$h/$多$-h$。
比如$H_2+\frac{1}{2}O_2=H_2O\ \Delta H=-h$
表示一个单位氢气与半个单位氧气生成一个单位水,放出$h$单位热量。
或者说一个单位氢气的内能加上半个单位的氧气的内能,比一个单位水的内能多$h$。
因为系数没有要求,所以上式等价于$2H_2+O_2=2H_2O\ \Delta H=-h$
因为广义下任何反应都是可逆的,于是上式还等价于$H_2O=H_2+\frac{1}{2}O_2\ \Delta H=h$

加减消元法:

盖斯定律:若一反应为二个反应式的代数和时,其反应热为此二反应热的代数和。也可表达为在条件不变的情况下,化学反应的热效应只与起始和终了状态有关,与变化途径无关。
也就是说,我们可以根据已知的热化学方程式,做上面提到的两种等价变换,再把若干方程式按照等式的法则做加减法,可以得到新的热化学方程式。下面举两个例子:
例$1$
$\begin{array}{ll} C+O_2=CO_2\ & \Delta H=h_1——① \\ CO+\frac{1}{2}O_2=CO_2\ & \Delta H=h_2——②\end{array}$
求$2C+O_2=2CO$的焓变。
解:②反向变换得
$CO_2=CO+\frac{1}{2}O_2\ \Delta H=-h_2——③$
$①+③$,左右两边消去$CO_2$得
$C+\frac{1}{2}O_2=CO\ \Delta H=h_1-h_2$
最后两边同时$\times 2$得
$2C+O_2=2CO\ \Delta H=2(h_1-h_2)$
例$2$
已知
$\begin{array}{ll} H_2+\frac{1}{2}O2=H_2O\ & \Delta H=h_1——① \\ CH_4+2O_2=CO_2+2H^2O\ & \Delta H=h_2——② \\ C_2H_4+3O_2=2CO_2+2H_2O\ & \Delta H=h_3——③ \\ C_2H_6+\frac{7}{2}O_2=2CO_2+3H_2O\ & \Delta H=h_4——④\end{array}$
求$C_2H_4+H_2=C_2H_6$的焓变。
解:$①+③+$(反向$④$)得
$C_2H_4+H_2=C_2H_6\ \Delta h_1+h_3-h_4$
可以发现题目中的$②$为多余条件。


题解

先明确一下题目中所说的$m$,其实就是不同物质数,以下也用此表示。

这道题的两个难点分别是输入和高斯消元。

先来讲我的读入方式,发现都是一个小数+一个物质,于是可以用先读小数再读$string$就好了,用$map$记录每种元素有没有出现过即可。

再将更复杂的高斯消元,发现方程数小于未知数的个数,但是我们没有必要求出这个未知数的具体大小。

我的方法好像不是正解,就是将行改为$n+1$,列改为$m+1$消元即可,最后答案就是$Map[n+1][m+1]$。

出题人说没有卡精度,但是我被卡精度了……

调了好长时间才过……

时间复杂度:$\Theta(n^3)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
struct rec{double a;string s;}e[210][210];
map<string,int> mp;
int n,m;
string str;
double Map[210][210],del;
double ans;
double gauss()
{
	for(int i=1;i<=n;i++)
	{
		int flag=i;
		for(int j=i+1;j<=n;j++)
			if(fabs(Map[j][i])>fabs(Map[flag][i]))flag=j;
		for(int j=1;j<=m+1;j++)
			swap(Map[i][j],Map[flag][j]);
		if(fabs(Map[i][i])<1e-8)continue;
		double b=Map[i][i];
		for(int j=i;j<=m+1;j++)Map[i][j]/=b;
		for(int j=1;j<=n+1;j++)
		{
			if(j==i) continue;
			double b=Map[j][i];
			for(int k=i;k<=m+1;k++)
				Map[j][k]-=Map[i][k]*b;
		}
	}
	if(fabs(Map[n+1][m+1])<1e-8)return 0;
	return -Map[n+1][m+1];
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n+1;i++)
	{
		int res=0,now=1;
		while(1)
		{
			res++;
			cin>>e[i][res].a>>e[i][res].s;
			if(!mp[e[i][res].s])mp[e[i][res].s]=++m;
			e[i][res].a*=now;
			string str;cin>>str;
			if(str[0]==‘=‘)now=-1;
			if(str[0]==‘H‘)
			{
				if(i!=n+1)cin>>e[i][++res].a;
				break;
			}
		}
	}
	for(int i=1;i<=n+1;i++)
	{
		int res=0;
		while(!e[i][++res].s.empty())
			Map[i][mp[e[i][res].s]]=e[i][res].a;
		Map[i][m+1]=e[i][res].a;
	}
	printf("%.1lf",gauss());
	return 0;
}


rp++

原文地址:https://www.cnblogs.com/wzc521/p/11686895.html

时间: 2024-10-25 07:28:29

[CSP-S模拟测试]:炼金术士的疑惑(模拟+数学+高斯消元)的相关文章

[CSP-S模拟测试]:天空龙(模拟)

题目描述 奥西里斯之天空龙很喜欢颜色,有一天他找到了三种颜色——红黄蓝.奥西里斯有$a$个红色,$b$个黄色,$c$个蓝色,他想用画出最好的画,可是需要至少$x$个红色,$y$个黄色和$z$个蓝色,似乎并不够.别担心,奥西里斯会魔法!他可以把任何两个同种颜色转化为一个另一种颜色!请问他能不能完成呢? 输入格式 第一行一个正整数$t$表示数据组数.接下来$t$行每行六个整数分别表示$a,b,c,x,y,z$. 输出格式 每组数据输出一行,如果可以就输出$"YES"$,否则输出$"

[CSP-S模拟测试]:表达式密码(模拟)

题目传送门(内部题87) 输入格式 从文件$expression.in$中读入数据.输入一行,一个字符串$S$,表示原表达式,保证为合法表达式 输出格式 输出到文件$expression.out$中.一个字符串,表示使表达式结果最大的符号添加方案. 题解 样例输入1: 10+20-30 样例输出1: 10+20-3+0 样例输入2: -3-4-1 样例输出2: -3-4-1 样例输入3: -200+351-1600 样例输出3: -2+0+0+351-1+600 数据范围与提示 设字符串长度为$

[CSP-S模拟测试]:简单的玄学(数学)

题目描述 有$m$个在$[0,2^n)$内均匀随机取值的整型变量,球至少有两个变量取值相同的概率.为了避免精度误差,假设你的答案可以表示成$\frac{a}{b}$的形式,(其中$(a,b)=1$),你需要输出$a$和$b$对${10}^6+3$取模后的值. 输入格式 第一行两个正整数$n,m$. 输出格式 一行两个整数,它们的含义如题所述. 样例 样例输入1: 3 2 样例输出1: 1 8 样例输入2: 1 3 样例输出2: 1 1 样例输入3: 4 3 样例输出3: 23 128 数据范围与

[CSP-S模拟测试]:工业题/a(数学)

题目传送门(内部题39) 输入格式 第一行:四个正整数$n$.$m$.$a$.$b$.第二行:$n$个正整数,第$i$个表示$f(i,0)$.第三行:$m$个正整数,第$i$个表示$f(0,i)$. 输出格式 第一行:一个整数,代表$f(n,m)\mod 998244353$. 样例 样例输入: 4 4 3 2 1 3 5 7 2 4 6 8 样例输出: 50807 数据范围与提示 $20\%$的数据:$n,m\leqslant 10,a,b\leqslant 3,f(i,0),f(0,i)\l

[CSP-S模拟测试]:Seat(概率DP+数学)

题目描述 有$n+2$个座位等距地排成一排,从左到右编号为$0$至$n+1$.最开始时$0$号以及$n+1$号座位上已经坐了一个小$G$,接下来会有$n$个小$G$依次找一个空座位坐下.由于小$G$们坐得太近就容易互相搏弈,每个小$G$会找一个当前离最近的小$G$距离最远的座位坐下.如果有多个备选的座位,这个小$G$会等概率选择其中一个.给出$n$,求第$i$个坐下的小$G$坐在$j$号座位的概率,对$P$取模.具体来说,如果答案化为最简分数可以表示为$\frac{a}{b}$,你需要输出$a\

[CSP-S模拟测试]:Median(暴力+模拟)

题目描述 定义两个数列: $$S=\{S(1),S(2),...,S(n)\}\text{和}S_2\{S_2(1),S_2(2),...,S_2(n)\}$$ $$S(k)=(p_k\times k)\mod w,where\ p_k\ is\ the\ kth\ prime\ number$$ $$S_2(k)=S(k)+S(\left\lfloor\frac{k}{10}\right\rfloor+1)$$ 令$M(i,j)$表示$S_2(i)$到$S_2(j)$的中位数(个数为奇数就是中

[CSP-S模拟测试]:神炎皇(数学)

题目描述 神炎皇乌利亚很喜欢数对,他想找到神奇的数对. 对于一个整数对$(a,b)$,若满足$a+b\leqslant n$且$a+b$是$ab$的因子,则称为神奇的数对.请问这样的数对共有多少呢? 输入格式 一行一个整数$n$. 输出格式 一行一个整数表示答案,保证不超过$64$位整数范围. 样例 样例输入: 21 样例输出: 11 数据范围与提示 对于$20\%$的数据,$n\leqslant 1000$:对于$40\%$的数据,$n\leqslant 100000$:对于$60\%$的数据

模拟测试20191016

T1:导弹袭击 首先我们发现只有诸如$a_{i}>a{j}$ && $b_{i}<b_{j}$的导弹有用 则我们可以把导弹按照$a$升序排序后离散化使得对于任意$i<j$,有$b_{i}<b_{j}$ 一个很显然的性质就是我们不需要关注$A,B$的具体值,而只关注$\frac{A}{B}$的值 将题目中的柿子列出来 $$ \frac{A}{a_{i}}+\frac{B}{b_{i}} \leq \frac{A}{a_{j}}+\frac{B}{b_{j}} $$ 化

模拟测试(vj)

做这份模拟测试,已经崩溃了,英文看不懂,题意理解错.到结束了只a了第一题,人生陷入了低谷,于是花了一天的时间终于把不会的弄明白了,在这里写一份总结~ T1,简单的模拟,如果打枪打中一支鸟,将这个位置设为0,并向两边扩散,注意这个位置一定要有鸟. 代码~ #include<bits/stdc++.h> using namespace std; int a[30000]; int n,m; int main() { cin>>n; for(int i=1;i<=n;i++) ci