重郵第八屆ACM大賽-預賽題解報告
A. a x b (Ⅰ)
簽到題
- 學會如何處理多組資料
- 注意爆int
B. 多關鍵字排序
水題
- 讀入的時候可以考慮使用
scanf(" (%d,%d)", &x, &y);
- 排序可以直接使用std::sort,當然也可以自己寫,但氣泡排序等高複雜度演算法無法通過該規模的資料;考慮使用快排、歸併排序等高效演算法
- 可以自己寫結構體,當然這裡推薦使用std::pair;如果自己寫結構體,需要寫cmp函式或過載<運算子
更詳細的STL用法可以自行搜尋或參考Cplusplus
標程裡使用的是讀入掛…
code
C. 全排列
水題
使用std::next_permutation瞬秒
當然也可以自己遞迴生成,這裡提供一個js覺得很勁的寫法
D. 三數和為零
一個可行的做法是:
- 列舉
ai - 查詢set內是否有
−ai - 將所有的
ai+aj(j<i) 插入set
這裡使用std::set會超時,所以我手寫了一個hashset code
當然這題做法還有很多,您們可以自己研究(比如使用two pointers,複雜度可以達到
背一下鍋
這道題的資料水了,放了一些錯誤的做法過。
很多人是列舉兩個數
對於
賽後資料已經更新了,這樣水過的同學可以嘗試改一下。
E. a x b (Ⅱ)
模擬高精度乘法
當然也可以用java的BigInteger水過
由於C++的高精度本弱寫得太醜,就貼個java吧(逃
code
F. 資料結構
- 對於操作1、2、3、4,我們可以使用std::deque雙端佇列來維護
- 對於操作5,我們並不需要真的reverse整個序列,只需要用一個變數標記一下。若有標記,則操作1、2互換,3、4互換,標記與否不影響操作6
- 對於操作6,用一個std::map維護即可
具體參見:
code
G. 矩陣鏈乘
動態規劃經典例題,可參考算導等資料
設
時間複雜度
標程使用記憶化搜尋實現
code
H. 滿射函式
該問題的另一種等價敘述為:
n個不同的球放入m個不同的盒子中,要求每個盒子中至少有一個球,問有多少種不同的放法。
這和第二類斯特林數(集合的劃分數)很像,事實上答案就是S(n,m)*m!,因為集合劃分實際上是把m個盒子看成相同的,而m個盒子的全排列就是m!
但是本題n和m較大,如果用遞推法求斯特林數會超時
這裡需要使用容斥原理
設
則
利用容斥原理,可以得到:
大組合數的計算方法可以使用預處理階乘,求逆元可以使用擴充套件歐幾里得演算法或者費馬小定理+快速冪演算法
當然這題由於組合數下標固定,上標遞增,也可以不預處理階乘,直接遞推
code
I. a x b (Ⅲ)
FFT模板題…
直接模擬乘法複雜度
乘法運算可以看成卷積和運算,事實上卷積和的一種求法就是不進位乘法
使用fft做快速卷積即可,複雜度
這裡建議手寫complex,比STL自帶的快不少
code
J. 行列式求值
模擬題
回憶線性代數,求行列式值的常用方法是將行列式化為上三角行列式,則行列式的值就是主對角線元素的乘積。在模p域下,加減乘都很好操作,而因為p是質數,所以模p域內任意非0元都存在乘法逆元,除法也可以轉化為乘它的乘法逆元。
code
K. 炸彈爆破
模型可以轉化為一個有向圖
若炸彈A能引爆炸彈B(B的位置在A的爆炸範圍內),則連一條A->B的有向邊
列舉兩個炸彈的組合,可以在
建完圖後,求強連通分量,縮點,找入度為0的點
入度為0則表示該聯通分量不可能由其他聯通分量(炸彈)引爆,只能付出代價手動引爆
而要引爆某個連通分量,顯然引爆其中代價最小的炸彈最為划算
code