1. 程式人生 > >NOI2015 程式自動分析

NOI2015 程式自動分析

題目大意:
給出一系列變數的等式約束和不等式約束,要求判定其中是否有矛盾;
變數下標最大值≤10^9;
約束數量≤10^5;

題解:
這是NOI2015最水的題了;
首先,分開等式約束和不等式約束;
等式約束用並查集儲存;
不等式約束先用陣列存著,等約束輸入完畢後再判定是否與等式約束有矛盾;
即判斷不等式兩端變數是否屬於同一集合
到這裡,70分到手;
變數有10^9個?
空間只有512MB?
要是開10^9大小的並查集肯定爆空間;
但約束只有10^5個,即能用得到的變數最多隻有2*10^5個;
網上說離散化,我是不懂的,離散化不是計算幾何的嗎?
uoj上一位哥們乾脆上了個map;
即按輸入的順序給變數重新編號,
將重新編號後的變數的編號用於並查集中,原編號儲存在map中,從而大大減少空間用量;
這樣,每次並查集合並或查詢根結點時都需要在map中按原編號查詢新編號,用時O(logn);
總用時O(n*logn),n≤10^5,可以過;
於是,他的程式總用時2265ms,倒數第二,我用了AVL樹,原倒數第二,hehe;

再考慮本題;
本題只用到了search(),和insert()操作,沒有排序啊什麼的;
考慮用連結串列維護的hash;
用一個2*10^5的陣列T儲存原編號;
再用一個2*10^5的陣列next儲存下一元素位置;
用一個p(模的數)大小的陣列儲存每個hash值對應連結串列的表頭;
變數新編號就是它在T陣列中的位置,例T[2015]=124785,那麼124785的新編號為2015;
這樣查詢用時O(1),總用時O(n);
該演算法在uoj上排名第三(前兩個見鬼去吧),用時725ms;
注:uoj是一個相當好的oj,它支援瀏覽別人的程式碼,甚至可以通過hack來阻止別人的騙分程式碼拿到滿分,
唯一的缺點就是題目較少(因為比較新);