• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            (從網上某神犇處轉載的)
            比如2006年11月的月賽:
            ace.delos.com/NOV06
            然后就傻掉了……
            其它的類似這樣搞就行了囧……

            posted @ 2011-10-04 23:36 Mato_No1 閱讀(2199) | 評論 (3)編輯 收藏

            本沙茶自從NOI2011結束以來,陷入危機,具體表現為:編程速度變慢;想題目的時候容易想偏;編程時比較不專注,容易想到別的東西上去;容易受到雜念的干擾。這次危機是本沙茶至今為止遇到的最嚴重的一次危機,到了9月中下旬,這次危機發展到極限,幾乎到了絕望的邊緣。因此,本沙茶在長達1個多月的時間里,沒有什么實質性的進展,也沒有在這個空間里作總結。

            在十一假期的前四天里,本沙茶努力調整狀態,終于在10月4日(也就是今天),正式擺脫了危機,恢復到了正常狀態。以后,本沙茶會繼續在這里作總結,同時爭取盡可能大的提高,在本賽季的各項比賽中竭盡全力,爭取好成績。

            感謝BZOJ對本沙茶在擺脫危機過程中的幫助。
            Orz WJMZBMR等神犇

            posted @ 2011-10-04 23:28 Mato_No1| 編輯 收藏

            CF 掛0……
            掉DIV2……
            真不知道世界上還有木有比我還弱的……

            真的陷入危機了么?
            ——————————————————————————————————————————
            不,我不能讓自己陷入危機!!!

            posted @ 2011-09-04 14:53 Mato_No1 閱讀(656) | 評論 (0)編輯 收藏

            此帖用于記錄NOI2011團體對抗賽的各版本(代碼)更新情況。
            ————————————————————————————————————————————————————
            【2011年7月28日】
            目前代碼框架(Program0.cpp)已經完成。
            NOI2011團體對抗賽安徽隊的代碼名稱初步定為:Docx
            ————————————————————————————————————————————————————
            【2011年7月29日】
            Docx I已經完成,代碼長度(包括注釋)為5368Bytes
            版本說明:
            (1)對優勢分數G的計算為G2.1版本;
            (2)啟發函數還比較弱;
            目前由于測評機問題,暫時無法測試,只有看晚上的練習賽了。
            ————————————————————————————————————————————————————
            【2011年7月30日】
            今天禿然發現了Docx I的一個嚴重錯誤:在判定是否有炸彈的時候把true和false弄反了,結果導致炸彈根本無法使用。
            現在改掉了之后(仍然命名為Docx I),TEST結果仍然不是很理想,只能虐別人的一些初等版本,高等版本(比如那個"I Hate Zerg"的版本2)根本木有辦法。
            目前正在改進啟發函數,爭取在明天下午之前出Docx II。
            ————————————————————————————————————————————————————
            【2011年8月1日】
            真驚險!最后時刻終于找到了問題所在,并且把Docx II經最后一步改進得到的版本命名為Docx III,提交到排位賽。
            最后結果……還行,第3名……只是嚴重懷疑有強省故意放水……
            大概明天正式分組就能出來了……
            ————————————————————————————————————————————————————
            【2011年8月2日】
            分組結果已經出來,安徽隊的形勢還是比較有利的……

            好了,在8月10日下午以前都不用再管團體對抗賽了……全力沖刺個人競賽……
            ————————————————————————————————————————————————————
            【2011年8月10日】
            團體對抗賽最后沖刺。
            今天把幾個地方的系數改了一下,一些看起來很傻的決策也得到了修正。不過晚上練習賽的結果仍然很不理想……
            算了,明天1/4決賽等著被血洗吧囧……

            現在還有一點時間,亂搞一下吧囧……
            ————————————————————————————————————————————————————
            【2011年8月11日】
            最終結果:八強,1/4決賽中被湖南血洗

            顯然是一個預想之中的結果……還是應驗了那句話:團體對抗賽碰到湖南就是找死……
            這次,本沙茶真的已經盡力了……
            明年再來吧……

            posted @ 2011-07-28 22:08 Mato_No1 閱讀(1155) | 評論 (1)編輯 收藏

            在圖DFS的過程中,給每個點設立兩個附加值dfn和low。dfn[i]表示點i被發現(變灰)的時間,也就是“發現次序”。而low[i]表示i能夠到達的dfn值最小的i的祖先結點或i本身的dfn值,即low[i]=min{dfn[i], dfn[j], low[k]}(其中j為滿足以下條件的點:圖中存在邊<i, j>且這條邊在遍歷到的時候j在棧中(這個棧的具體說明見下);k為遍歷樹中i的某個子結點,)。

            Tarjan算法就是在圖DFS過程中,得到每個點的dfn值和low值,并且設立一個棧,點變灰的時候入棧,在某個點i的low值真正確定后(容易發現,一個點只有變黑了,它的low值才真正確定),若low[i]=dfn[i],則將棧中點i及其上面的所有點全部彈出(這些點一定是以i為根的子樹中的結點,因為它們比i后入棧,卻比i先出棧),這些點組成一個強連通分支,這樣在圖DFS遍歷完后,即可得到所有的強連通分支。

            下面證明結點i變黑時,若low[i]=dfn[i],則
            i及其所有未出棧的后代組成一個強連通分支。
            證明這個需要分兩步:
            【1】i的所有未出棧的后代與i處于同一個強連通分支。
            設j是i的某個后代且j在i變黑時尚未出棧。顯然i可達j,因此只需證明j可達i。
            在遍歷樹中,從i到j路徑上除i外的所有結點的low值都小于dfn值(否則,設這條路徑上存在結點k,k≠i,low[k]=dfn[k]。因為k比i先變黑,所以在k變黑時,其所有后代就會出棧,這與j在i變黑時仍未出棧矛盾,故這樣的結點k不存在)。設dfn[x]=low[j],則根據low的定義以及low[j]<dfn[j]得,必然是j的祖先且從j先往下再經過一條逆向邊可以到達點x,并且,x不可能是i的祖先(若x是i的祖先,則i先往下再經過一條逆向邊可達x,因此dfn[x]>=low[i],又因為dfn[x]<dfn[i],所以low[i]<dfn[i],這與low[i]=dfn[i]矛盾),也就是x位于路徑i->j上且x≠j。若x=i,則j可達i,結束,否則先從j到達x,再將x當成j,繼續往上……這樣最終必然能到達點i。因此j可達i,即j與i處于同一個強連通分支。
            【2】不是i的未出棧的后代不與i處于同一個強連通分支。
            設j不是i的未出棧的后代,則j有兩種情況:
            (1)j是i的后代,且在i變黑前已經出棧:
            此時,i->j路徑上必然存在一個點k,滿足k≠i,且dfn[k]=low[k](這樣的k可能有多個,此時取最深的那個為k),當k變黑時j出棧。這時,由與【1】類似的推導過程可得,j不斷往上到達的最上層祖先結點也只能是k,到不了i,故j不可達i,也即j與i不處于同一個強連通分支;
            (2)j不是i的后代,考慮當i變黑時,j的顏色:
            <1>白色:此時,若i可達j,則j在i變黑前,就會成為i的后代,這與j不是i的后代矛盾,故i一定不可達j,也即j與i不處于同一個強連通分支;
            <2>灰色:若j為灰色,則j一定是i的祖先,若i可達j,根據low的定義可得,必有low[i]<=dfn[j]<dfn[i],這與low[i]=dfn[i]矛盾,故i不可達j,也即j與i不處于同一個強連通分支;
            <3>黑色:若j不是i的后代,且比i先變黑,則必然是在i變灰前j已經變黑。這時,若j可達i,則i會成為j的后代,也即j是i的祖先,這樣在i變黑時,j應為灰色,矛盾,故j不可達i,也即j與i不處于同一個強連通分支;
            綜上可得,i、j一定不處于同一個強連通分支。故原命題得證,也就證明了Tarjan算法是可以求出有向圖的所有強連通分支的。

            時間復雜度分析:由于每個點都要入棧一次,出棧一次,每條邊都要被訪問一次,所以總時間復雜度為O(N+M)。

            寫代碼時注意事項:
            (1)要用人工棧實現DFS,不可用遞歸,防止爆棧;另外注意不要將這個人工棧與上面說到的“棧”弄混,本沙茶下面的代碼中,用于搜索、回溯的人工棧為stk0,而用于找強分支的棧為stk;
            (2)注意邊界情況;
            (3)注意在出棧時要將V值設為2;

            (4)注意計算low[i]時,需要考慮非i的祖先,但仍在棧中的結點,它們也被視為i的“祖先”。

            核心代碼:
            void solve()
            {
                re(i, n) {V[i] 
            = vst[i] = 0; st[i] = E[i].next;}
                
            int x, y, x0, tp, tp0, ord = 0, No = 0;
                
            bool fd;
                re(i, n) 
            if (!V[i]) {
                    stk[tp 
            = 0= stk0[tp0 = 0= i; vst[i] = 1; low[i] = dfn[i] = ++ord; V[i] = 1;
                    
            while (tp0 >= 0) {
                        x 
            = stk0[tp0]; fd = 0;
                        
            for (int p=st[x]; p != x; p=E[p].next) {
                            y 
            = E[p].b;
                            
            if (!V[y]) {
                                fd 
            = 1; stk[++tp] = stk0[++tp0] = y; vst[y] = 1; low[y] = dfn[y] = ++ord; V[y] = 1; st[x] = E[p].next; break;
                            } 
            else if (vst[y] && dfn[y] < low[x]) low[x] = dfn[y];
                        }
                        
            if (!fd) {
                            V[x] 
            = 2;
                            
            if (low[x] == dfn[x]) {while (stk[tp] != x) {vst[stk[tp]] = 0; w[stk[tp--]] = No;} vst[x] = 0; w[stk[tp--]] = No++;}
                            
            if (tp0) {x0 = stk0[tp0 - 1]; if (low[x] < low[x0]) low[x0] = low[x];} tp0--;
                        }
                    }
                }
                re(i, n) {reslen[i] 
            = 0for (int p=E[i].next; p != i; p=E[p].next) if (w[i] == w[E[p].b]) reslen[i]++;}
            }


            posted @ 2011-07-28 20:57 Mato_No1 閱讀(1786) | 評論 (0)編輯 收藏

            【背景(神犇不要鄙視)】
            本沙茶今年AHOI的時候,遇到裸的最佳匹配的題,竟然把KM算法搞忘了,幸虧是WJMZBMR神犇保佑,臨時亂弄一通,想起來了……這MS反映出了本沙茶以前在看某些經典算法的時候看得不深,木有理解透徹……
            前幾天又遇到一道最佳匹配的題,發現KM算法竟然又忘了……米辦法,只有把這個搞死人的算法的具體過程重新看了一遍,終于懂了……
            【KM算法及其具體過程】
            (1)可行點標:每個點有一個標號,記lx[i]為X方點i的標號,ly[j]為Y方點j的標號。如果對于圖中的任意邊(i, j, W)都有lx[i]+ly[j]>=W,則這一組點標是可行的。特別地,對于lx[i]+ly[j]=W的邊(i, j, W),稱為可行邊
            (2)KM算法的核心思想就是通過修改某些點的標號(但要滿足點標始終是可行的),不斷增加圖中的可行邊總數,直到圖中存在僅由可行邊組成的完全匹配為止,此時這個匹配一定是最佳的(因為由可行點標的的定義,圖中的任意一個完全匹配,其邊權總和均不大于所有點的標號之和,而僅由可行邊組成的完全匹配的邊權總和等于所有點的標號之和,故這個匹配是最佳的)。一開始,求出每個點的初始標號:lx[i]=max{e.W|e.x=i}(即每個X方點的初始標號為與這個X方點相關聯的權值最大的邊的權值),ly[j]=0(即每個Y方點的初始標號為0)。這個初始點標顯然是可行的,并且,與任意一個X方點關聯的邊中至少有一條可行邊
            (3)然后,從每個X方點開始DFS增廣。DFS增廣的過程與最大匹配的Hungary算法基本相同,只是要注意兩點:一是只找可行邊,二是要把搜索過程中遍歷到的X方點全部記下來(可以用vst搞一下),以進行后面的修改;
            (4)增廣的結果有兩種:若成功(找到了增廣軌),則該點增廣完成,進入下一個點的增廣。若失敗(沒有找到增廣軌),則需要改變一些點的標號,使得圖中可行邊的數量增加。方法為:將所有在增廣軌中(就是在增廣過程中遍歷到)的X方點的標號全部減去一個常數d,所有在增廣軌中的Y方點的標號全部加上一個常數d,則對于圖中的任意一條邊(i, j, W)(i為X方點,j為Y方點):
            <1>i和j都在增廣軌中:此時邊(i, j)的(lx[i]+ly[j])值不變,也就是這條邊的可行性不變(原來是可行邊則現在仍是,原來不是則現在仍不是);
            <2>i在增廣軌中而j不在:此時邊(i, j)的(lx[i]+ly[j])的值減少了d,也就是原來這條邊不是可行邊(否則j就會被遍歷到了),而現在可能是;
            <3>j在增廣軌中而i不在:此時邊(i, j)的(lx[i]+ly[j])的值增加了d,也就是原來這條邊不是可行邊(若這條邊是可行邊,則在遍歷到j時會緊接著執行DFS(i),此時i就會被遍歷到),現在仍不是;
            <4>i和j都不在增廣軌中:此時邊(i, j)的(lx[i]+ly[j])值不變,也就是這條邊的可行性不變。
            這樣,在進行了這一步修改操作后,圖中原來的可行邊仍可行,而原來不可行的邊現在則可能變為可行邊。那么d的值應取多少?顯然,整個點標不能失去可行性,也就是對于上述的第<2>類邊,其lx[i]+ly[j]>=W這一性質不能被改變,故取所有第<2>類邊的(lx[i]+ly[j]-W)的最小值作為d值即可。這樣一方面可以保證點標的可行性,另一方面,經過這一步后,圖中至少會增加一條可行邊。
            (5)修改后,繼續對這個X方點DFS增廣,若還失敗則繼續修改,直到成功為止;

            下面分析整個算法的時間復雜度:每次修改后,圖中至少會增加一條可行邊,故最多增廣M次、修改M次就可以找到僅由可行邊組成的完全匹配(除非圖中不存在完全匹配,這個可以通過預處理得到),故整個算法的時間復雜度為O(M * (N + 一次修改點標的時間))。而一次修改點標的時間取決于計算d值的時間,如果暴力枚舉計算,這一步的時間為O(M),優化:可以對每個Y方點設立一個slk值,表示在DFS增廣過程中,所有搜到的與該Y方點關聯的邊的(lx+ly-W)的最小值(這樣的邊的X方點必然在增廣軌中)。每次DFS增廣前,將所有Y方點的slk值設為+∞,若增廣失敗,則取所有不在增廣軌中的Y方點的slk值的最小值為d值。這樣一次修改點標的時間降為O(N),總時間復雜度降為O(NM)。

            需要注意的一點是,在增廣過程中需要記下每個X、Y方點是否被遍歷到,即fx[i]、fy[j]。因此,在每次增廣前(不是對每個X方點增廣前)就要將所有fx和fy值清空。

            代碼:

            void init_d()
            {
                re(i, n) E[i].pre 
            = E[i].next = i; m = n;
            }
            void add_edge(int a, int b, int len)
            {
                E[m].a 
            = a; E[m].b = b; E[m].len = len; E[m].pre = E[a].pre; E[m].next = a; E[a].pre = m; E[E[m].pre].next = m++;
            }
            inline 
            int dist(int x, int y, int x0, int y0)
            {
                
            return abs(x - x0) + abs(y - y0);
            }
            bool dfs(int x)
            {
                
            int y, x0; fx[x] = _FLAG;
                
            for (int p=E[x].next; p != x; p=E[p].next) {
                    y 
            = E[p].b;
                    
            if (lx[x] + ly[y] > E[p].len) {
                        
            if (lx[x] + ly[y] - E[p].len < slk[y]) slk[y] = lx[x] + ly[y] - E[p].len;
                    } 
            else if (fy[y] != _FLAG) {
                        fy[y] 
            = _FLAG; x0 = z[y];
                        
            if (x0 == -1 || dfs(x0)) {z[y] = x; return 1;}
                    }
                }
                
            return 0;
            }
            void solve()
            {
                re(i, n) {
                    lx[i] 
            = -INF;
                    
            for (int p=E[i].next; p != i; p=E[p].next) if (E[p].len > lx[i]) lx[i] = E[p].len;
                }
                re(i, n0) {ly[i] 
            = 0; z[i] = -1;}
                
            int d;
                re(i, n) {
                    re(j, n0) slk[i] 
            = INF; _FLAG++;
                    
            while (!dfs(i)) {
                        d 
            = INF; re(j, n0) if (fy[j] != _FLAG && slk[j] < d) d = slk[j];
                        re(j, n) 
            if (fx[j] == _FLAG) lx[j] -= d;
                        re(j, n0) {slk[j] 
            = INF; if (fy[j] == _FLAG) ly[j] += d;}
                        _FLAG
            ++;
                    }
                }
                res 
            = 0; re(i, n) res += lx[i]; re(i, n0) res += ly[i];
            }


             

            posted @ 2011-07-23 22:14 Mato_No1 閱讀(7620) | 評論 (9)編輯 收藏

            這次總算木有再莫名其妙地掛掉了……交了三題,全AC……

            【D、E題到現在理解不了,樣例是怎么來的?】

            【最新消息:已發現D題的數據有問題,詳見官網】

            posted @ 2011-07-23 02:30 Mato_No1 閱讀(360) | 評論 (0)編輯 收藏

            【1】IOI2009 hiring(這個在各大OJ上都找不到囧,只能看這里了囧,第11頁)
            可以發現本題就是求一個比率rate,使得第i個人(如果用的話)工資為rate*Qi,并且還要滿足以下兩個限制條件:
            (1)每人的最低工資限制:第i個人如果用的話,有rate*Qi>=Si,即rate>=Si/Qi;
            (2)總開銷限制:rate*所有用的人的Q值之和<=W,即所有用的人的Q值之和<=W/rate。
            這樣,可以先將所有人按照(S/Q)的值遞增排序,然后枚舉需要用的最后一個人(排序后的,也就是S/Q值最大的那個人),設為i,則總花費最省的做法顯然是取rate=Si/Qi。然后根據(2)式得出“所有用的人的Q值之和”的最大值W0=W/rate,其中,第i個人是必須要用的,故將W0值先減去Qi(若W0<Qi,則第i個人不可使用),剩下的問題就變成了在第0~(i-1)個人中(排序后的)選取一些人,使得他們的Q值之和不大于W0,并且選取的人盡可能多。顯然這可以用貪心來實現,即選取Q值最小的若干個人。接下來,由于題目中N<=500000,說明需要用數據結構來優化,可是Q的上限只有20000且Q為正整數,因此,線段樹是最好的選擇。建立一棵表示[1, 20000]的線段樹,每個結點存放兩個額外的值:sz和sum,分別表示Q值位于該結點代表的區間內的人的總數以及這些人的Q值總和。然后,需要解決上述子問題時,從根結點開始考察結點的sz值,不斷往下找即可(這有點像平衡樹的找第K小的操作)。
            總時間復雜度:O(N * (log20000 + logN))(還有排序的時間)
            代碼

            【2】RQNOJ469
            先按照任意一種屬性(這里為A)遞增排序,然后枚舉值i,排序后第1位~第i位的全部給A(看A屬性,它們中A屬性最大的一定是i),排序后第(i+1)位及以后的,看其B、C兩種屬性的大小,若B屬性更小就看B屬性,若C屬性更小就看C屬性,然后得出兩種屬性的最大值即可。因此可以得到下面的算法:先排序,然后將所有的毛的B或C屬性(哪種更小就看哪種)插入平衡樹(這里需要兩棵平衡樹,一棵存放B屬性的值,一棵存放C屬性的值),然后遞增枚舉i(注意i=0的情況不要漏掉),將第i位的B或C屬性在平衡樹中刪除,然后找出兩棵平衡樹中的最大值即可。
            但是需要注意一種特殊情況:所有的毛都看同一個屬性,此時按照上面的算法可能求不出最優解,比如:
            10 6 5
            10 2 8
            此時,第1個C屬性更小,第2個B屬性更小,若第1個看C屬性,第2個看B屬性,則總和為5+2=7,而如果兩個都看B屬性則總和為6。此時就需要特判(預先求出三種屬性中的最大值),然后再用上面的算法求解,就能保證求出最優解了。
            代碼

            【3】PKU2985
            并查集+平衡樹基本操作,水題,不解釋。
            代碼

            【4】HNOI2011 括號匹配Brackets(目前可以看這個帖子
            Splay Tree維護序列問題。對于一段括號序列A[1..len],定義優先級P[0..len]如下:
            P[0]=0
            P[i]=P[i-1]+1(i>0且A[i]為左括號)
            P[i]=P[i-1]-1(i>0且A[i]為右括號)
            然后,Splay Tree的每個結點需要記錄一個Z值和M值,分別表示該結點代表的括號序列中最后一個元素的優先級和優先級最小的元素的優先級。則可以證明:這段括號序列調整至平衡至少需要改變的括號數目為(-M+K+1) / 2,其中K=Z+((-M+1)/2)*2(注意這里的/是整除),此外由于有swap和invert兩個操作,因此需要記錄RM、TM、RTM值,分別表示將該括號序列執行swap操作后的序列的M值、執行invert操作后的序列的M值,以及同時執行swap和invert操作后序列的M值。
            不過,本題需要嚴重注意的是:雖然replace操作的標記(代碼中的mk0)會覆蓋掉swap(代碼中的mk1)和invert(代碼中的mk2)操作的標記,但是在下放標記的時候,需要對三種標記逐一判斷,mk0和mk1、mk2并不是不能共存的!因為有可能先打上mk0標記后再打上mk1或mk2標記。
            本題雖然是靜態的,但仍然不能使用線段樹,因為線段樹無法支持整體翻轉(rev)操作。
            代碼

            posted @ 2011-07-23 02:24 Mato_No1 閱讀(1171) | 評論 (0)編輯 收藏

                 摘要: 【原題見這里】很明顯的精確覆蓋的模型,12個零件,再加上它們經過旋轉、翻轉后的不同形狀,共60種,每種又可以放在不同的位置(只看最左上的那個珠子)一種零件的一種位置就是一行。列(限制)有兩種:每個格子只能放一個(55列),以及每個零件(注意是每個零件,不是每種零件)只能用一次(12列),共67列。預先放的那些零件可以看成預先選中的行。然后DLX精確覆蓋即可。下面是DLX精確覆蓋的幾個易疵點:(1)...  閱讀全文

            posted @ 2011-07-20 23:07 Mato_No1 閱讀(1165) | 評論 (2)編輯 收藏

            昨天在刷PKU1084的時候,調了很久,發現原來那樣實現有缺陷。(原來的實現見這里

            在重復覆蓋問題中,刪去一整列的操作(delcol)是斷開該列除了初始結點外的所有結點的左右鏈(delLR),這樣,如果有一些行預先已被選中,則刪去這一行(準確來說是對這一行所有結點執行delcol操作),這時就會出現問題,因為在刪去這一行的最后一個結點的時候,其左、右鏈都指向其本身,此時就無法刪掉這個結點。解決這一問題的辦法是除了在矩陣中引入列頭以外,還要引入行頭(rowh),并且保證行頭不刪掉。這樣在刪掉一整行的時候就不會出問題了。但是,如果這樣的話,需要在搜索過程中執行delcol操作前進行特判,保證不刪掉行頭結點(比如將行頭結點的U、D域置為-1),并且,在求啟發函數h()值的時候也要防止在行頭處出現問題,可以將行頭結點的行列號均置為0。

            而在精確覆蓋問題中,刪去一整列的操作是斷開結點的上下鏈而不是左右鏈,因此在刪去一整行時就不需要引入行頭結點。

            下面是PKU1084的AC代碼:
            #include <iostream>
            #include 
            <stdio.h>
            using namespace std;
            #define re(i, n) for (int i=0; i<n; i++)
            #define re1(i, n) for (int i=1; i<=n; i++)
            #define re3(i, l, r) for (int i=l; i<=r; i++)
            const int MAXN = 60, MAXM = 55, INF = ~0U >> 2;
            struct dlnode {
                
            int r, c, U, D, L, R;
            } d[(MAXN 
            + 1* (MAXM + 1)];
            int _n, n, m, nodes, rowh[MAXN + 1], cols[MAXM + 1], B[5][5][4], res;
            bool A[MAXN + 1], vst[MAXN];
            void init_d()
            {
                re3(i, 
            0, m) {d[i].U = d[i].D = i; d[i].L = i - 1; d[i].R = i + 1;} d[0].L = m; d[m].R = 0;
                nodes 
            = m; re1(i, n) {rowh[i] = ++nodes; d[nodes].L = d[nodes].R = nodes; d[nodes].U = d[nodes].D = -1;}
                re1(i, m) cols[i] 
            = 0;
            }
            void add_node(int r, int c)
            {
                cols[c]
            ++; d[++nodes].r = r; d[nodes].c = c;
                d[nodes].U 
            = d[c].U; d[nodes].D = c; d[c].U = nodes; d[d[nodes].U].D = nodes;
                
            int rh = rowh[r]; d[nodes].L = d[rh].L; d[nodes].R = rh; d[rh].L = nodes; d[d[nodes].L].R = nodes;
            }
            void delLR(int x)
            {
                d[d[x].L].R 
            = d[x].R; d[d[x].R].L = d[x].L;
            }
            void delUD(int x)
            {
                d[d[x].U].D 
            = d[x].D; d[d[x].D].U = d[x].U;
            }
            void resuLR(int x)
            {
                d[d[x].L].R 
            = d[d[x].R].L = x;
            }
            void resuUD(int x)
            {
                d[d[x].U].D 
            = d[d[x].D].U = x;
            }
            void delcol(int x)
            {
                
            for (int i=d[x].D; i != x; i=d[i].D) delLR(i);
            }
            void resucol(int x)
            {
                
            for (int i=d[x].U; i != x; i=d[i].U) resuLR(i);
            }
            void prepare()
            {
                
            int x = 0;
                re(i, _n) {
                    re(j, _n) {B[i][j][
            0= ++x; B[i][j][1= x + _n; B[i][j][2= x + _n + 1; B[i][j][3= x + _n + _n + 1;}
                    x 
            += _n + 1;
                }
                x 
            = 0;
                re(i, _n) re(j, _n 
            - i) re(k, _n - i) {
                    x
            ++;
                    re(t, i
            +1) {
                        add_node(B[j][k 
            + t][0], x);
                        add_node(B[j 
            + t][k][1], x);
                        add_node(B[j 
            + t][k + i][2], x);
                        add_node(B[j 
            + i][k + t][3], x);
                    }
                }
                
            int rh;
                re1(i, n) 
            if (A[i]) {
                    rh 
            = rowh[i];
                    
            for (int j=d[rh].R; j != rh; j=d[j].R) delcol(j);
                }
                res 
            = n;
            }
            int h()
            {
                re1(i, m) vst[i] 
            = 0;
                
            int z = 0;
                
            for (int i=d[0].R; i; i=d[i].R) if (!vst[i]) {z++; vst[i] = 1for (int j=d[i].D; j != i; j=d[j].D) for (int k=d[j].R; k != j; k=d[k].R) vst[d[k].c] = 1;}
                
            return z;
            }
            void dfs(int dep)
            {
                
            int h0 = h(); if (dep + h0 >= res) returnelse if (!h0) {res = dep; return;}
                
            int mins = INF, c0; for (int i=d[0].R; i; i=d[i].R) if (!cols[i]) returnelse if (cols[i] < mins) {mins = cols[i]; c0 = i;}
                
            for (int i=d[c0].D; i != c0; i=d[i].D) {
                    delcol(i); 
            for (int j=d[i].R; j != i; j=d[j].R) if (d[j].U != -1) delcol(j);
                    dfs(dep 
            + 1);
                    
            for (int j=d[i].L; j != i; j=d[j].L) if (d[j].U != -1) resucol(j); resucol(i);
                }
            }
            int main()
            {
                
            int tests, _n0, x;
                scanf(
            "%d"&tests);
                re(testno, tests) {
                    scanf(
            "%d%d"&_n, &_n0);
                    n 
            = _n * (_n + 1<< 1; m = 0; re1(i, _n) m += i * i; init_d(); re1(i, n) A[i] = 0;
                    re(i, _n0) {scanf(
            "%d"&x); A[x] = 1;}
                    prepare();
                    dfs(
            0);
                    printf(
            "%d\n", res);
                }
                
            return 0;
            }

            posted @ 2011-07-20 12:28 Mato_No1 閱讀(1506) | 評論 (0)編輯 收藏

            僅列出標題
            共12頁: First 4 5 6 7 8 9 10 11 12 
            亚洲精品白浆高清久久久久久| 国产精品成人久久久久久久| 久久人人爽人人爽人人爽 | 久久99中文字幕久久| 99久久亚洲综合精品成人| 亚洲一级Av无码毛片久久精品| 7777精品久久久大香线蕉| 国产精品毛片久久久久久久| 九九精品99久久久香蕉| 久久精品国产精品亜洲毛片| 中文国产成人精品久久不卡| 久久国产成人| 国产成人精品免费久久久久| 亚洲伊人久久成综合人影院 | 国产成人久久精品一区二区三区| 97久久精品人人做人人爽| 亚洲欧洲日产国码无码久久99| 99久久人人爽亚洲精品美女| 日韩精品无码久久久久久| 青春久久| 久久99精品九九九久久婷婷| 久久久久久久久久久久中文字幕| 欧美精品一区二区久久| 久久综合综合久久97色| 国产成人久久精品一区二区三区 | 亚洲国产天堂久久综合| 国产精品内射久久久久欢欢| 97久久精品午夜一区二区| 伊人久久大香线蕉亚洲五月天| 内射无码专区久久亚洲| 国产精品成人久久久久三级午夜电影 | 狠狠色婷婷久久一区二区三区 | 色偷偷91久久综合噜噜噜噜| 国产真实乱对白精彩久久| A级毛片无码久久精品免费| 久久精品国产福利国产秒| 99精品国产在热久久无毒不卡 | 亚洲欧美国产精品专区久久| 精品久久久久久无码免费| www亚洲欲色成人久久精品| 精品国产一区二区三区久久蜜臀|