河南省第八屆ACM A 挑戰密室 詳細題解

2021-07-06 07:22:00 字數 4161 閱讀 4399

挑戰密室

時間限制:1000 ms | 記憶體限制:65535 kb

難度:4

描述 r組織的**dr. kong 為了尋找丟失的超體元素,不幸陷入wto密室。dr. kong必須盡快找到解鎖密碼逃離,否則幾分鐘之後,wto密室即將**。

dr. kong發現密室的牆上寫了許多化學方程式中。化學方程式,也稱為化學反應方程式,是用化學式表示物質化學反應的式子。化學方程式反映的是客觀事實。因此書寫化學方程式要遵守兩個原則:一是必須以客觀事實為基礎;二是要遵守質量守恆定律。

化學方程式不僅表明了反應物、生成物和反應條件。同時,化學計量數代表了各反應物、生成物物質的量關係,通過相對分子質量或相對原子質量還可以表示各物質之間的質量關係,即各物質之間的質量比。對於氣體反應物、生成物,還可以直接通過化學計量數得出體積比。例如:2naoh+h2so4=na2so4+2h2o

經過多次試探、推理,dr. kong發現密碼是4位數字,就隱藏在化學方程式等號後的第乙個分子中,其分子量就可能是密碼(若分子量不足4位,前面加0)。

好在dr. kong還記得牆上各化學方程式用到的化學元素的原子量如下:nc

oclsh

alca

znna

1312

1635322

2740

6523

你能幫dr. kong盡快找到密碼嗎?

輸入 第一行: k,表示有k個化學方程式;

接下來有k行,每行為乙個化學方程式

輸出 對於每個化學方程式輸出一行:即密碼。

樣例輸入

3 2c+o2=2co

2naoh+h2so4=na2so4+2h2o

ca2co3+h2o=ca2(oh)2+co2

樣例輸出

0056

0142

0116

提示 2≤k≤8 ,化學方程式的長度不超過50, 所有原子,分子的數量不超過9.小括號最多一層.

** 第八屆河南省程式設計大賽

今年省賽的題目,當時熱身賽裡就有類似題目,沒做出來,沒想到省賽正式賽又出了,orz,現在我回頭看這道題難度似乎並沒有那麼大,只是需要考慮的情況多了點,而且重要的是需要打表,昨天靜下心來花了三個小時慢慢寫最終也是一次ac了,成就感是必須有的啊。

總結了下,本題為了簡化思路需要考慮到的幾個關鍵點有:

1、化學式開頭可能存在分子數量,放在for迴圈外處理下,之後就不用考慮數字出現在字母前的情況了(其他數字只可能出現在原子後或者括號後面)

2、每個原子必定是以大寫字母開始的,所以遍歷字串的過程中只要遇到大寫字母就開始一次分析就ok了。這樣就不用考慮下標每次向後移動幾位這個讓人頭疼的問題了、下標一直++就ok了,絕對不會遺漏、因此帶來的耗時增加幾乎可以忽略不計,測試例子不會太多而且字串並不長。

3、關於括號問題:之前的想法是一直處理知道碰到括號就把括號裡面的字串提取扔進另外寫的乙個函式中計算,後來想想其實括號裡外的字元處理方式相差其實是不大或者說差不多完全相同的。那麼就採用遞迴,遇到括號就把括號裡面的內容遞迴進去,設定變數接收函式返回值,最終加和到總的結果裡,這樣就無意中解決了多層括號巢狀的情況(雖然題目中保證並不會出現 - -。)

4、關於打表,建議採用map來做,stl裡的東西合理利用起來省好多事情而且通常來說是比較安全的。至少我個人是比較喜歡使用的。

以下是我第一次寫的**:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

using

namespace

std;

map m;

int jisuan(string a)

else

if (islower(a[i + 1]))//下一位是小寫字母;

else

if (isdigit(a[i + 2]))

else

}else

//下一位不是小寫字母;

else}}

}int jieguo = 0;

map::iterator it;

for (it = m.begin(); it != m.end(); it++)

return jieguo;

}int main()

while (1)

int s = 0;

int fenzishu;

if (a[0] >= '2'&&a[0] <= '9')

fenzishu = a[0] - '0';

else

fenzishu = 1;

string tmp;

int len = a.length();

for (int i = 0; i < len; )

else

if (isupper(a[i]))

else

if (islower(a[i + 1]))//下一位是小寫字母;

else

if (isdigit(a[i + 2]))

else

}else

//下一位不是小寫字母;

else}}

else

if (a[i]=='(')

int kuohao_jieguo=jisuan(kuohao);

if (isdigit(a[j + 1]))

else}}

int jieguo = 0;

map::iterator it;

for (it = m.begin(); it != m.end(); it++)

s += jieguo;

s *= fenzishu;

if (s < 1000)

printf("0");

if (s < 100)

printf("0");

if (s < 10)

printf("0");

printf("%d\n", s);

}return

0;}

這麼臃腫的**肯定不滿意啦,況且這麼多的下標控制。比賽的時候如果這樣寫肯定是要**的啊有木有~!

下決心優化:通過以上提到的幾點,將**進行優化:

#include

#include

#include

#include

#include

using

namespace

std;

map m;

int jisuan(string a)

if (m_count.count(tmp) == 0)//原子個數累加;

m_count[tmp] = yuanzishu;

else

m_count[tmp] += yuanzishu;

}else

if (a[i] == '(')//如果遇到括號;

int fenzishu_kuohao = 1;//儲存小括號後的數字;

if (isdigit(a[i + 1]))

fenzishu_kuohao = a[i + 1] - '0';

s += jisuan(kuohao)*fenzishu_kuohao; //重點來了,將括號裡的內容遞迴進去進行計算得到返回值即相對質量;}}

int jieguo_kuohaowai = 0;//儲存括號外的原子相對質量和;

map::iterator it;

for (it = m.begin(); it != m.end(); it++)//根據各原子數量查表計算;

s += jieguo_kuohaowai;//結果加和;

s *= fenzishu;//記得乘上可能存在的分子個數;

return s;//返回相對質量;

}int main()

int s = jisuan(a);//傳參計算;

printf("%04d\n", s);

}return

0;}

採用遞迴寫法,**長度從254行縮減到了92行,並且更容易看懂理解。順帶解決了多重括號巢狀的問題。之前在網上竟然找不到這道題的題解。如果不是優化到百行以內。像我這種弱渣怎麼好意思發題解 = =/.

第八屆acm省賽 A挑戰密室(模擬)

time limit 1 sec memory limit 128 mb submit 29 solved 10 submit status web board r組織的 dr.kong 為了尋找丟失的超體元素,不幸陷入 wto密室。dr.kong 必須盡快找到解鎖密碼逃離,否則幾分鐘之後,wto密...

第八屆河南省省賽總結

這次比賽的吐槽點太多了,算是參加過的最奇葩的一場比賽吧,題目是鄭州大學老師出的,太有侷限性了,基本上除了水題就是圖論,其他知識點乙個沒有,希望有關老師能夠開放一點,把省賽的水平提上去,不然這樣發展下去感覺真的參加省賽的意義不太大了,就只是玩玩而已。熱身賽的話一道簡單的類似於表示式求值的題目,一道水題...

河南省第八屆ACM省賽 引水工程

時間限制 2000 ms 記憶體限制 65535 kb 難度 3 描述南水北調工程是優化水資源配置 促進區域協調發展的基礎性工程,是新中國成立以來投資額最大 涉及面最廣的戰略性工程,事關中華民族長遠發展。南水北調工程 旨在緩解中國華北和西北地區水資源短缺的國家戰略性工程。就是把中國長江流域豐盈的水資...