• <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>

            blockade寫疵了……
            在貪心的部分的一個x++忘寫了囧……
            再加上Day1完跪,估計本沙茶這次AH Top10都進不去了囧……明年省集訓隊有危險了囧……(據最新消息,由于AH太弱了,Top10還是穩的囧……)

            看來這么長的綜合題代碼不對拍確實很危險……
            但又有誰讓我寫得這么慢木有時間對拍了呢……

            為什么掛得這么慘呢?
            基本的模板寫得太不熟了,一遇到綜合題就慢,drive和blockade掛掉都是這個原因囧……
            還有,一遇到長代碼的題就畏懼……本沙茶在寫blockade代碼的時候,連寫add_edge時手都在抖,心發慌……以至于這個200-行的代碼寫了2h+……

            之前的N多模擬賽,本沙茶都考得很好,但是有個毛用……畢竟當時這種類型的題木有出……

            剩下就木有可說的了囧……雖然這次掛了,但是只要吸取教訓,下次一定能翻身!!!!!!!!!!!
            AHOI2013 我要復仇!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

            Orz AK的大神!!
            @hqztrue
            @roosephu

            posted @ 2012-11-19 17:58 Mato_No1 閱讀(849) | 評論 (0)編輯 收藏

            【Day1】
            vigenere:不說了;

            game:
            方法一(本沙茶在現場的做法,60分):
            設i的左右手為A[i]和B[i]。二分最大的金幣數D,則第i個人要滿足其前面所有人(包括國王)的A之積不超過S[i] = (D+1) * B[i] - 1。
            考慮站在最后的那個人,顯然除了他以外的所有人(包括國王)的A之積不能超過他的S值,如果木有人滿足此條件則無解,否則取滿足此條件的A值最大的人,放最后(因為若某個合法方案最后不是滿足此條件的A值最大的人,則把那個A值最大的人與他交換,仍然是合法方案),然后刪掉這個人,轉化為子問題,直到所有人都刪掉為止,此時必然有解。
            此方法時間復雜度為O(N2 * log2MAXW),其中MAXW為D的上限,由于60%的數據D<=109,所以MAXW取109
            顯然這個方法是不能再加高精度了,否則必T,問題是計算所有人的A之積時會超過long long范圍,解決方法:由于A和B的上限是104,D的上限是109,所以有解時必然有所有人的A之積<=109 * 104 * 104 = 1017,因此在過程中若超過這個值,必定無解,直接卡掉。

            方法二(正解):
            把所有的人按照A*B遞增排序,就一定是最優解,剩下的就不解釋了(需要高精度乘除單精度)。
            證明:
            若某方案不是將所有人按照A*B遞增排序的,則必然存在i使得A[i]*B[i]>A[i+1]*B[i+1](這里的i是排序后的編號,不是原來的編號),下證交換i和(i+1)之后解必然不會變差。
            設i前面所有人(包括國王)的A值之積為S1。
            交換前,i的金幣數為S1/B[i],(i+1)的金幣數為S1*A[i]/B[i+1];
            交換后,i的金幣數為S1*A[i+1]/B[i],(i+1)的金幣數為S1/B[i+1];
            注意這里S1*A[i]/B[i+1]顯然不小于S1/B[i+1],而S1*A[i]/B[i+1]-S1*A[i+1]/B[i]=S1*(A[i]*B[i]-A[i+1]*B[i+1])/(B[i]*B[i+1])>0,因此交換前(i+1)的金幣數不小于交換后i和(i+1)的金幣數,而除了i和(i+1)外,其他人在交換前后金幣數都不變,因此總的金幣數的最大值不會變大,即解不會變差。證畢。

            這兩種解法都是貪心,但它們是從不同的角度入手的——方法一是“分階段貪心”,證明需要分別證最優子結構性質和貪心選擇性質;方法二是“排序貪心”——在一類有關最優順序的問題中,一般解法不是貪心,就是二分圖或網絡流模型(當然小數據也可以狀壓),如果用貪心,只要找到一種排序方法(對某個值排序),使得若不這樣排序則把相鄰逆序的元素交換后能夠得到不更差的解,做法就是正確的。

            drive:(本沙茶想出正解了,可是實在寫不完,后來交暴力了囧——真真真真真真真真真真真真真真真真真真真真真真真真真真真真真真悲劇)
            首先求出S1[i]和S2[i]分別表示i往右最近的和第二近的位置,這個用平衡樹可以解決;
            然后,每個位置i拆成兩個點i.A和i.B,分別表示從這里出發,A先開和B先開。i.A往S2[i].B(如果有的話)連一條邊,邊權為兩位置距離,i.B往S1[i].A(如果有的話)連一條邊,邊權為兩位置距離。由于不會有環(S1[i]、S2[i]均>i),所以是森林。
            然后,設F1[i]和F2[i]分別為從i走到根結點,A開的長度和B開的長度,這個BFS一下就可以了囧。
            對于第一問,設W[i]為從i往上走,總長不超過X0時最遠能走到哪里,顯然只要從下到上求W,類似單調隊列亂搞即可;求出W后,枚舉每個點i,用記錄的F1和F2值可以求出i到W[i]路徑上A開的和B開的長度,找比值最小的即可;
            對于第二問,可以在求出森林后用樹的路徑剖分搞,但更好的做法是倍增:設SUM[i][k]表示從i往上走2k條邊的總長度,SUM可以在預處理中求出,做第二問時,只需要在SUM里調就行了,一次操作的時間復雜度O(log22N)。
            顯然這是個數據結構綜合題,巨繁瑣(估計代碼要超過10K),本沙茶當時花了1h+寫,后來發現腫么也不可能寫完了,就交暴力了囧(早知道一上來就寫暴力了,這樣或許能想出來game的正解啊啊啊啊啊啊啊啊啊……哭死……)

            總之Day1跪得不成人形了……

            【Day2】
            mod: 不說了;

            classroom:線段樹是可以AC的,只不過要把兩個操作(找最小值和區間減法)放一起;
            當然,本題的正解是,二分M0,然后看前M0個操作是否能全部滿足:將每個操作(l, r, D)拆成(1, r, D)和(1, l-1, -D)(當l>1時),這樣所有操作的左端點都是1了,設S[i]為右端點為i的所有操作的D之和,這個顯然可以在線性時間內得到,則點i的變化量就是S[i..N]之和,這個在求出S[i]后從后到前掃描一下即可得出,也是線性,如果所有的變化量加上原來的值都不小于0,則前M0個操作都能滿足,否則就不是都能滿足。
            這樣,時間復雜度仍是O(NlogM)的。更好的方法是,借鑒倍增的思想,如果前M0個可以滿足,就把前M0個都滿足(把所有點都加上變化量),接下來就不用考慮前M0個操作了,只在后面繼續二分。這樣,算法的時間復雜度就是線性的了。

            blockade:
            【首先每個軍隊往上走當然是最好的,但不能在根上停住。
            因此,二分最長時間D(注意D<=5*10^13),然后先看不能走到根的軍隊,一直往上走直到時間到了。
            然后看能走到根的,先讓他們全到根上,然后,對于那些“還有葉結點木有被控制的”根的子樹(防止斷句錯誤),用那些走到根上的來控制,用貪心解決……
            本沙茶就這么寫的,寫了180+行,也查完了,可是在結束前5min時突然發現漏了一種情況——
            某些能到根的軍隊可以不走到根,直接停在根的子結點處,控制這棵子樹。
            可是已經來不及了,最后就木有考慮這種情況……而且這種情況還比較普遍……】
            這種情況的解決辦法:
            如果某個軍隊能走到根,但讓它再走一步,走回到它所在的那個根的子結點,就來不及了的話,就讓它停在根的子結點處,控制它自己的子樹。這是因為,如果它去幫別的子樹,必然就有第三個軍隊要來幫它。設它所在的那個根的子結點為B,它去幫的子結點為A,幫它的第三個軍隊所在的根的子結點為C,由于它自己走不回來,所以第一次走到根的子結點處的剩余時間T<2*W(root, B),而它能去幫別的子結點,所以T>=W(root, A)+W(root, B_,可得出W(root, A)<W(root, B)。第三個軍隊能來幫它,所以第三個軍隊剩余的時間>=W(root, B)+W(root, C_,自然>W(root, A)+W(root, C),所以這第三個軍隊也能去幫A,因此,讓原來的軍隊停在B,第三個軍隊去幫A,也是合法方案。
            注:本題灰常麻煩,需要用到樹DFS、BFS、倍增(這個和drive腫么一樣啊囧……),本沙茶寫的時候還用上了線段樹囧……

            總之Day2也跪了,但不像Day1那么慘囧……
            總之Day2比Day1跪得更慘囧……

            posted @ 2012-11-14 21:04 Mato_No1 閱讀(898) | 評論 (2)編輯 收藏

            水題就不說了囧……

            【1】Oct.30 TYVJ “掃地”杯III NOIP2012模擬賽 day1
            (本沙茶這個其實木有參加,是之后捉的……還好AK了囧……Orz liouzhou_101!!)
            第一題:
            若n=1,則只有當y=x*x時才有唯一解x(這個一定要特判);
            若n>1,由柯西不等式得(a22+a32+...+an2)(1+1+...1(n-1個1)) >= (a2*1+a3*1+...+an*1)2
            即(n-1)(y-a12)>=(x-a1)2,當且僅當a2~an全部相等時等號成立。
            顯然a1的最大、小值一定是零點,也就是求方程(n-1)(y-a12)=(x-a1)2的解的問題,若Δ<0則無解,否則求兩解之積,可用Vieta定理得出。

            第三題:
            先求出最短路圖(求出S到每個點的最短距離dist0[]和每個點到T的最短距離dist1[],然后邊<i, j>屬于最短路圖當且僅當dist0[i]+<i, j>長度+dist1[j]等于S-T最短路長),然后那些能炸掉的點就是最短路圖的S-T割點(當然S、T本身不能算,另外,最短路圖其實應該是個有向圖,但這里當做無向圖處理),只要對S、T所在的連通塊做Tarjan即可。
            注意這里最短路的求法:SPFA或許也能過,但由于其不穩定,在比賽的時候如果時間夠的話還是寫Dijk+heap吧囧……

            【2】Nov.2 TYVJ 「Clover 10」杯HE兩校聯賽(第二輪Day1)
            (這個也木有參加,是之后捉的……另外說一下,第二題的題目描述與數據不符)
            第三題:
            正解見This_poet神犇的空間。
            這里說一下本沙茶的方法(70分):
            設F[i][s]表示對X[1..i]進行設置,范圍是[1..s],且從1能夠“走出去”(走到大于i的結點)的方案總數,這里有s>i。
            枚舉“指出去”(X值大于i)的最小的結點為j(1<=j<=i),則有
            F[i][s]=∑(F[j-1][i] * (s-i) * si-j),1<=j<=i。
            邊界:F[0][i]=1(本身木有意義,在乘的時候作為單位元)
            這很容易理解。j是要指出去的,因此i+1<=X[j]<=s,有(s-i)種;對于X[1..j-1],由于j是指出去的最小結點,所以它們都不能指出去,X值范圍1..i,但是它們必須“指出j-1",就是走到j及其后面的部分,否則就會被困住,自然也就走不出去了,所以是F[j-1][i];對于j+1..i,它們可以隨便指,1<=X值<=S,因此是si-j
            但是,這個遞推式再也無法優化下去了,題目要求O(N2)顯然無法辦到。
            而在正解中,我們關心的不是從1能不能走出i,而是從1最遠能走到哪里。這時列出來的遞推式就很容易優化到O(N2)。所以,在遞推和DP問題中,思路的不同,將會引發完全不同的結果,當一個遞推式/轉移方程無法優化下去的時候,可以換一個思路來求解。

            【3】Nov.3 TYVJ 「Nescafé 29」杯HE兩校聯賽(第二輪Day2)
            第一題:
            二分r,求出每個半圓能覆蓋到的線段,再看這些線段的并是否為[0, x0]即可。問題就是求線段并的操作是比較易疵的。
            首先將所有線段按照左端點遞增排序,然后掃描每條線段,并記錄目前線段達到的最右位置(就是右端點最大值)maxr,若某條線段的左端點大于前面的maxr則不能覆蓋,掃描完了以后,再看第一條線段的左端點和所有線段的maxr是否符合要求即可。
            但是,對于本題要注意:(1)由于有可能相離,因此最后的線段數可能不足N條,尤其要注意一條線段都木有的情況;(2)(極其易疵)題目只要求覆蓋線段[0, x0]即可,因此,即使在x0右邊發現了中斷處(左端點大于前面maxr),也木有關系!!(本沙茶當時就在這里搞疵了,跪了2個點);

            第二題:
            本沙茶當時使用搜索騙的……可是它的數據實在太弱,本該AC的(最后還是跪了一個點,原因是卡時:ZZZ = ?? / m0,忘了考慮m0=0的情況);
            首先求出圖的每個連通塊,如果某連通塊內的所有結點初始權值之和不為零,無解。否則求出這個圖的最小生成森林(用Kruskal),作為初始解(其實很多情況下這就是最優解囧)。
            然后開始DFS,使用改變搜索順序優化:先考查兩端點權值都不為零且為相反數的邊(因為轉移之后可產生兩個0點),再考查兩端點權值都不為零且不為相反數的邊(轉移之后可產生一個0點,注意雙向轉移),最后考查兩端點權值有一個為零的邊(將0點轉移,不會產生新的零點),其它的決策顯然不明智。此外每條邊只能轉移一次。
            當然直接這樣搜肯定是要T的,但最優解會很快求出,因此可以卡掉。這題可以加啟發函數,但本沙茶不加也木有事囧……

            第三題:
            遞推式不說了。注意滿足條件的樹的高度的范圍其實很小(<=16),所以在找到高度上下界之后是不會T的。注意對于結果小于10^8的處理(不需輸出多余的0),此時N<=34;

            【4】Nov.5 VIJOS NOIP2012模擬賽第三彈
            第一題:
            容易證明,最優解中蟲洞的左端點一定是最左的點。
            二分最大距離dist,然后離最左的點距離<=dist的顯然都能走到,>dist的則只能使用蟲洞。設離最左的點距離>dist的左起第一個點為S,則從S往右枚舉每個點為蟲洞右端點時,離S的距離和離最右點的距離是否都不大于dist,若都小于,則右端點可以在這里,dist符合條件。

            【5】Nov.7 TYVJ NOIP2012提高組模擬賽day1
            全是水題,不說了。注意第二題是保留整數而不是四舍五入,第三題的“差”不是“差的絕對值”!!!!!!!!!!!!!!!

            【6】Nov.8 TYVJ 「Poetize 10」杯NOIP2012提高組模擬賽day2
            第一題:
            首先要模型轉化一下,題目就是:在一棵樹上,每個結點都有一個權值,除根結點外,每個結點都有一個容量(這個容量在題目中是體現在父邊上的),選定若干結點,使得樹中除根結點外的每個結點子樹中選定結點的權值之和都不大于其容量,問最多能選多少結點。
            由于數據范圍小,本沙茶用類似樹形背包的DP硬搞掉了,其實是可以貪心的囧……將結點按權值遞增排序,每次選擇一個所有祖先容量全部足夠的權值最小的結點,最后得到的一定是最優解。
            證明:由于決策之間不互相影響,最優子結構性質顯然滿足,下證貪心選擇性質。設目前所有祖先容量全部足夠的權值最小的結點為A,某方案中權值比A小的結點的選定情況(就是之前的狀態)與選A的方案相同,但木有選A。設該方案中選定的權值不小于A且與A的LCA深度最大的結點為B,LCA(A, B)=P,由于B的權值不小于A,所以若將B刪掉,A選上,其到根的路徑上P及其以上的部分顯然不會超過容量限制,對于P以下的部分,由于P是最深的LCA,因此P以下的部分根本木有被權值不小與A的結點所占用,因此肯定也不會有事,所以,將B刪掉、A選上,將得到一個不比原方案差的可行方案,所以貪心選擇性質滿足。綜上,貪心算法是正確的。

            第二題:
            先將區間按照右端點遞增排序,然后掃描:設目前區間的右端點為r,上一個區間的右端點為r0(這里忽略右端點相同的情況,即必有r>r0),則在[r0+1, r]這一段里的最優解有兩種可能:(1)若目前區間及其之后的區間內有左端點小于r的,則最優解為r;(2)若目前區間及其之后的區間的左端點全部不小于r,則[r0+1, r]這一段里各個值的能量總和均相同,為保證最小,最優解為r0+1。
            接下來的問題是如何快速求出E=r或r0+1時的能量總和。顯然在之前的區間里都不能獲得能量,后面的區間內,左端點小于等于E的區間的能量為左端點的值,否則為E。由于前面的區間的右端點都小于E,左端點自然小于等于E,所以“后面的區間內,左端點小于等于E的區間個數”就是全部區間內左端點小于等于E的區間個數,這個可以在預處理中將所有左端點遞增排序之后用二分查找得出,這些區間的左端點和值也可以記錄一個S值來得出,而左端點不小于E的區間個數就是(該區間及其后面的區間總數-左端點小于等于E的區間個數)。
            總時間復雜度O(NlogN);

            第三題:
            這個題真是折騰死人了囧……其實做法很簡單,但巨難想到……
            首先把待匹配字符串(設為A,匹配串設為B)展開成2倍的形式,所有的循環串就是所有長度為N的子串了囧……
            設F[i][j]為A(展開后的)第i個字符往前,至少到哪才能與B[0..j]匹配(也就是所有能與B[0..j]匹配的A[k..i]中的k的最大值)。顯然這樣一說,轉移方程就出來了囧:
            若B[j]="*",則F[i][j]=max{F[k][j-1], k<=i}
            若B[j]≠“*”,則F[i][j]=F[i-1][j-1](當A[i]=B[j]時)或-INF(當A[i]≠B[j]時),注意邊界:j=0時,B[j]必為"*"(根據下面的假設),此時F[i][j]=i+1(不是i!!為了后面的決策),而i=0時,若B[0..j]均為“*”則為1(不是0,同理)否則為-INF。
            對于max{F[k][j-1], k<=i}這里,顯然可以用輔助數組搞定,注意輔助數組是要滾動的,否則會MLE(其實F也可以滾動);
            接下來,若B[0]="*",則求出F之后只需要看對于每個i(i>=N-1,N為原長),F[i][M-1](M為B的長度)是否>=i-N+1即可,因為前面的部分都可以用這個*干掉。
            若B[0]≠"*",則將B最前面的不為"*"的部分拿出來,顯然這里是要硬性匹配的,因此先求出這里能匹配A的哪些位置(KMP用不用都可以),B剩下的部分按照B[0]="*"處理,只是最后在找的時候只能找原來B前面硬性匹配的部分可以配上的位置。
            若B里面木有"*",就是普通的字符串匹配的問題了,直接特判掉(同樣不必KMP)。這個比較容易漏掉。
            總時間復雜度O(NM)。
            ———————————————————————————————————————————————————
            大概也就這么多了囧……以后就再也木有NOIP級別的模擬賽了……真希望明年7月做NOI模擬賽也能像現在這樣啊囧……
            ———————————————————————————————————————————————————
            后記:模擬賽成績這么好,最終還是掛了……誰叫自己怕繁瑣題呢囧……

            posted @ 2012-11-09 21:36 Mato_No1 閱讀(651) | 評論 (0)編輯 收藏

            原題地址
            這是個超級大水題,我太沙茶了,想傻了N久……后來才反應過來……所以要寫一下作為警示。

            首先這個序列就是一個堆……
            因此,問題也就是說N個結點,權值剛好取遍1~N的堆的總數……
            設結果為F[N]。設N個結點的堆,左子樹有l個結點,右子樹有r個結點(顯然有l+r+1=N),則有
            F[N]=C(N-1, l) * F[l] * F[r]
            這個理解起來很容易囧……因為根結點只能是1,左子樹和右子樹顯然也都是堆,因此相當于在2~N中取l個數組成左子樹,剩下的數組成右子樹……又因為不管取哪些數,左右子樹的組成方法總數都是F[l]、F[r](只與次序有關)……這樣就得到上面的式子了囧……
            C(N-1, l)=N! / l! / r!,因此需要預處理出來A[i] = i! mod P,然后除法用逆元就行了囧……

            不過,本沙茶一開始想按照層數枚舉,然后相乘……自然搞不出來囧……后來又用暴力把N<=15的結果拿出來分析,想找到規律……結果毫無規律……后來又糾結了N久才想到上面這個……真正比賽的時候就悲劇了囧……所以要警示一下……

            代碼:
            #include <iostream>
            #include 
            <stdio.h>
            #include 
            <stdlib.h>
            #include 
            <string.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 re2(i, l, r) for (int i=l; i<r; i++)
            #define re3(i, l, r) for (int i=l; i<=r; i++)
            #define rre(i, n) for (int i=n-1; i>=0; i--)
            #define rre1(i, n) for (int i=n; i>0; i--)
            #define rre2(i, r, l) for (int i=r-1; i>=l; i--)
            #define rre3(i, r, l) for (int i=r; i>=l; i--)
            #define ll long long
            const int MAXN = 1000010, INF = ~0U >> 2;
            int n;
            ll MOD, A[MAXN], F[MAXN], res;
            void init()
            {
                cin 
            >> n >> MOD;
            }
            void prepare()
            {
                A[
            0= A[1= 1; re3(i, 2, n) A[i] = (A[i - 1* i) % MOD;
            }
            void exgcd(ll a, ll b, ll &x, ll &y)
            {
                
            if (b) {
                    ll _x, _y; exgcd(b, a 
            % b, _x, _y);
                    x 
            = _y; y = _x - (a / b) * _y;
                } 
            else {x = 1; y = 0;}
            }
            void solve()
            {
                F[
            0= F[1= 1int s = 1, l = 0, r = 0; ll x, y;
                re3(i, 
            2, n) {
                    
            if (l == s) {
                        
            if (r == s) {s += s + 1; l++;} else r++;
                    } 
            else l++;
                    F[i] 
            = F[l] * F[r] % MOD; F[i] = F[i] * A[i - 1% MOD;
                    exgcd(A[l], MOD, x, y); F[i] 
            = F[i] * x % MOD; if (F[i] < 0) F[i] += MOD;
                    exgcd(A[r], MOD, x, y); F[i] 
            = F[i] * x % MOD; if (F[i] < 0) F[i] += MOD;
                }
                res 
            = F[n];
            }
            void pri()
            {
                cout 
            << res << endl;
            }
            int main()
            {
                init();
                prepare();
                solve();
                pri();
                
            return 0;
            }

            posted @ 2012-10-30 21:35 Mato_No1 閱讀(1058) | 評論 (1)編輯 收藏

            和以前的總結一樣,那些是人都會搞的水題就不寫了囧……

            【1】 Sept.29 「Poetize」杯NOIP模擬賽 VI
            第一題(TYVJ P1962):
            枚舉及其優化。
            設F[i][S]為買的方案為S(用10位二進制表示)時,能不能表示出整數i(1<=i<=100),這個顯然可以預處理出來,然后將所有的狀態S按照“第一關鍵字為買的個數遞增,第二關鍵字為題目中的T遞增“排序。枚舉時,只需要按照排序后的順序從前到后枚舉狀態,找到第一個能表示出所有給出的整數的狀態即可。最壞情況下是10000*1024*10,會T,但題目中木有這樣的數據囧……

            第二題(TYVJ P1963):
            DP,思想非常另類的那種……
            每秒只有三種可能狀態:不進行(0)、準備進行(1)、進行(2),且0的下一個狀態是0或1,1的下一個是2,2的下一個是2或0,所以,假設時間是順序的,設F[i][j][x]表示前i秒中狀態1或2的有j秒,第i秒的狀態是x的最大值……(剩下的不說了,注意第一個狀態必須是0或1)
            下面考慮時間是環形的情況。可以發現,只要每兩個相鄰狀態都滿足“0的下一個是0或1,1的下一個是2,2的下一個是2或0”,就是合法的,不過,最后一個狀態也有下一個狀態:第一個(因為時間環形)。
            如果N=B,則所有的狀態都可以為1或2,只需要找到U值最小的那一秒,將它的狀態設為1,其它狀態設為2即可;(特判掉)
            如果N>B,則必然有狀態為0,也就是可以從它開始。所以,時間仍然可以按照順序的看待,只是注意若第一個狀態是2,則最后一個狀態不能是0——將第一個狀態為0、1的與為2的分開處理即可。
            注意,N=0與N=1時需要特判。

            第三題(TYVJ P1964):
            為了描述方便,可以將這個序列在格子中表示,如下圖,表示序列(3, 4, 5, 4, 6, 3):
            設最終的序列中每個數都為S。以下起第S行為界,上方的黑格需要消去,下方的白格需要補上。由于題目中只允許每次對連續的一段加1或減1,也就是消去同一行連續的一段黑格或補上同一行連續的一段白格,所以,容易證明,此時的最少操作次數就是(下起第S行上方各行的連續黑格段數之和+下起第S行下方各行的連續白格段數之和)。因此,問題就是枚舉S并維護這個和值。
            首先,預處理算出S=0的和值。此時只有黑格段沒有白格段。雖然行數很多,但本質不同的行最多只有N個,所以可以在O(N)時間內求出(當然先要進行一個O(NlogN)的排序)。具體求法就不說了囧……
            然后,考慮當S從0開始增加時,和值如何變化。顯然,S從x增加到x+1,和值的增量是(第x行的白格段數-第(x+1)行的黑格段數)。由于每一行都是白段與黑段交替的,所以,若第x行與第(x+1)行本質相同,則和值增量只可能是1(第x行最左邊和最右邊的格子都是白的)或0(第x行最左邊和最右邊的格子一白一黑)或-1(第x行最左邊和最右邊的格子都是黑的)。第一個和最后一個格子的顏色只與最初序列中第一個和最后一個數有關,且必然下起一開始若干行都是-1,然后是0,再然后是1……也就是和值一開始不斷減少,然后不變,然后不斷增加,那么,不變階段的和值就是最小值,其長度就是最小值的個數;
            問題是如果第x行到第(x+1)行發生改變腫么辦。此時,必然在原序列中有元素值為x,只需要把它們所在的位置的顏色從黑的改為白的即可。注意,在維護段數的時候,需要考慮到該格的相鄰的格子的顏色,還需要注意邊界。這樣的操作有N次,所以,時間復雜度是O(N)的。
            綜上,可以求出在每一個本質不變的行段內的最小值及其個數,取最小的即可。總時間復雜度為O(NlogN)(最初的排序)。

            【2】Oct.4 「Poetize」杯NOIP模擬賽 VII
            第三題(TYVJ P1993):
            注意到任意一個數能一步變換到達的數最多9*10+C(10, 2)=135個,只需要枚舉一下,然后用二分查找找出這個數在不在(不能用Hash,會扎堆),若在就連一條邊,然后求這個圖的s-t最短路即可,需要使用Dijk_heap(SPFA估計會被卡,注意手寫堆,不要priority_queue)。這樣對于題目中的數據可以卡線通過(最壞情況下仍然會T,估計正解是某種設計比較好的Hash)。注意,使用DL邊表時,需要在空間上作一些優化,否則可能MLE。

            【3】Oct.20 Tyvj三周年邀請賽
            第一題(TYVJ P2011):
            壓位即可。

            第三題(TYVJ P2013):
            首先轉移方程是很好搞的……F[i]為前i個數的最大權值,則F[i]=max{F[i-1], F[j]+A[j+1]*B[i], 0<=j<=i-2},邊界:F[0]=F[1]=0。問題是如何優化。
            首先,由于A、B序列木有單調性,一般的斜率優化是不行的囧……
            注意F[j]+A[j+1]*B[i],當F[j]求出來之后,這個其實是一個自變量為B[i]的一次函數,也就是一條直線(斜率A[j+1],縱截距F[j]),而且,由于B非負,所以這其實只是這條直線在y軸右側的部分(射線!!)
            本題需要維護的就是這些射線組成的下凸殼。注意,F數組是遞增的,也就是插入的射線的縱截距遞增。這樣,插入射線y=A[j+1]*x+F[j](x>=0)時,(0, F[j])這個點要么在原來的凸殼上(如果大于上一個F[j]),要么在原來的凸殼內部。
            如果在內部,則這條射線與原來的凸殼最多只有一個交點,因此只需要從左到右掃描原來的凸殼的邊(這些邊除了最右一條是射線外,其余都是線段),將一開始的在待插入射線下方的邊都刪去,直到找到一條邊與該射線相交或者所有部分都刪去為止。若某條邊與待插入射線相交,則刪去它在待插入射線下方的部分,再插入新射線,否則直接插入新射線;
            如果在凸殼上,那么新射線有兩種可能:一是斜率不大于上一條射線的斜率,此時該射線完全在凸殼外或凸殼上,直接舍棄;二是斜率大于上一條直線的斜率,此時,把原來凸殼上最左的那條邊刪掉,再按照內部的情況處理即可;
            求F[i]時,找到x=B[i]與凸殼的交點即可;
            顯然,這些邊可以用一個棧來維護(本沙茶一開始以為是隊列,寫完了以后才發現是棧……于是代碼中按照隊列的格式來寫的囧……),每條射線最多進棧一次,出棧一次,加上二分查找的時間,總時間復雜度O(NlogN)。
            寫的時候注意一些細節,尤其要注意的是,算出F[i]后不能馬上插入射線i,而要在F[i+1]算出后才能插入,因為j<=i-2!!(同樣的,一開始也只能插入0,不能插入1)

            代碼:
            P1962 P1963 P1964 P1993 P2013

            posted @ 2012-10-24 15:27 Mato_No1 閱讀(408) | 評論 (0)編輯 收藏

            原題地址
            本沙茶在2009年1月曾經在RQNOJ上捉過這題,那時候是很難的題,現在就很水了囧……(當然,本沙茶那個時候不會exKMP,是用暴力的,可是時間復雜度仍能是O(N3))。

            F[i][j]=min{F[i][k]+F[k+1][j],min{((j-i+1)/(k-i+1)的十進制位數)+2+F[i][k],k-i+1}, i<=k<j,第二項需要滿足原字符串[i..j]這一段恰好由[i..k]這一段的若干次復制得到}
            (加上k-i+1是因為對于以下三種重疊字符串,不壓縮比壓縮要短:AA型、AAA型、ABAB型)
            邊界:F[i][i]=1;

            問題是在上述方程的第二項里如何求出可行的k。顯然,只需要對[i..j]這一段作exKMP,求出nx,然后k可行當且僅當滿足:(1)nx[k+1]=j-k;(2)(k-i+1)|(j-i+1);

            不過,本題在寫exKMP的過程中會出現很囧的問題……由于下標不是從0開始,而是從i開始,所以很多地方關于下標的計算都要改掉,非常不方便,而且很容易疵掉。與其這樣,還不如把[i..j]這一段復制到一個新字符串里,下標從0開始。對于其它的某些字符串算法和數據結構,或許也是這樣囧……

            代碼:
            #include <iostream>
            #include 
            <stdio.h>
            #include 
            <stdlib.h>
            #include 
            <string.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 re2(i, l, r) for (int i=l; i<r; i++)
            #define re3(i, l, r) for (int i=l; i<=r; i++)
            #define rre(i, n) for (int i=n-1; i>=0; i--)
            #define rre1(i, n) for (int i=n; i>0; i--)
            #define rre2(i, r, l) for (int i=r-1; i>=l; i--)
            #define rre3(i, r, l) for (int i=r; i>=l; i--)
            #define ll long long
            const int MAXN = 110, INF = ~0U >> 2;
            int n, F[MAXN][MAXN], nx[MAXN], res;
            char ss[MAXN + 1], ss0[MAXN + 1];
            void init()
            {
                scanf(
            "%s", ss); n = strlen(ss);
            }
            int sol0(int l, int r)
            {
                
            int W = r - l + 1; re3(i, l, r) ss0[i - l] = ss[i];
                nx[
            0= W; nx[1= nx[0- 1; re(i, W) if (ss0[i] != ss0[i + 1]) {nx[1= i; break;}
                
            int k = 1, len, p = k + nx[k] - 1, x, y;
                re2(i, 
            2, W) {
                    len 
            = nx[i - k];
                    
            if (i + len <= p) nx[i] = len; else {
                        x 
            = p + 1; y = p - i + 1if (y < 0) {x++; y = 0;}
                        
            for (; x<=&& ss0[x]==ss0[y]; x++, y++) ;
                        nx[i] 
            = y; k = i; p = i + y - 1;
                    }
                }
                
            int res0 = INF, tmp, V;
                re2(i, 
            1, W) if (!(W % i) && nx[i] == W - i) {
                    V 
            = F[l][l + i - 1+ 2; tmp = W / i; while (tmp) {tmp /= 10; V++;}
                    
            if (W < V) V = W;
                    
            if (V < res0) res0 = V;
                }
                
            return res0;
            }
            void solve()
            {
                re(i, n) F[i][i] 
            = 1;
                
            int j, tmp;
                re2(x, 
            1, n) re(i, n-x) {
                    j 
            = i + x; F[i][j] = sol0(i, j);
                    re2(k, i, j) {tmp 
            = F[i][k] + F[k + 1][j]; if (tmp < F[i][j]) F[i][j] = tmp;}
                }
                res 
            = F[0][n - 1];
            }
            void pri()
            {
                printf(
            "%d\n", res);
            }
            int main()
            {
                init();
                solve();
                pri();
                
            return 0;
            }

            posted @ 2012-10-24 15:11 Mato_No1 閱讀(531) | 評論 (0)編輯 收藏

            原題地址
            首先,看這么小的范圍就知道,數學方法肯定搞不了……又想不到其它模型……只能用狀壓硬搞了囧……
            問題是,5^15穩T,如果能倒過來,15^5,就不會T了。
            可以發現,C值相同的顏色本質上是一樣的……因此,只需要保存目前C值為1、2、3、4、5的顏色各有多少種就行了囧……(當然在過程中還會出現C值為0的,即用完的顏色,不過0、1、2、3、4、5的和是顏色總數,而且從下面可以看出,C值為0的確實“木有用”);
            設F[s1][s2][s3][s4][s5][v]為涂完前若干個木塊(這個個數可以通過s1~s5算出,不過我們并不需要它囧……)后,C值為1~5的顏色各有s1~s5種,且這若干個中的最后一個涂的顏色還剩的C值為v(顯然0<=v<=4)。
            邊界:F[S[1]][S[2]][S[3]][S[4]][S[5]][0]=1,其余為0(S[i]為一開始C值為i的顏色種數)。
            計算F時,前推后(注意順序,是按照S[5]逆序最先,再依次是S[4]~S[1],都是逆序,v可任意定序),枚舉下一個木塊的顏色是現在還剩多少的,如果它與目前的這個(最后一個)剩的相同,則要減1,否則不減。具體的方程見代碼。
            注意細節:枚舉F的s1~s5下標時,都要N(顏色總數)開始枚舉,因為過程中某些s值會增加;

            本題的啟示就是,在設計狀壓DP的時候,如果正著來不行,可以反著來,或許就能設計出符合要求的解法。

            代碼:
            #include <iostream>
            #include 
            <stdio.h>
            #include 
            <stdlib.h>
            #include 
            <string.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 re2(i, l, r) for (int i=l; i<r; i++)
            #define re3(i, l, r) for (int i=l; i<=r; i++)
            #define rre(i, n) for (int i=n-1; i>=0; i--)
            #define rre1(i, n) for (int i=n; i>0; i--)
            #define rre2(i, r, l) for (int i=r-1; i>=l; i--)
            #define rre3(i, r, l) for (int i=r; i>=l; i--)
            #define ll long long
            const int n = 5, MAXM = 16, MOD = 1000000007;
            int m, S[n + 1];
            ll F[MAXM][MAXM][MAXM][MAXM][MAXM][n], res;
            void init()
            {
                scanf(
            "%d"&m); int x;
                re(i, m) {scanf(
            "%d"&x); S[x]++;}
            }
            void solve()
            {
                F[S[
            1]][S[2]][S[3]][S[4]][S[5]][0= 1int tmp;
                rre3(i5, m, 
            0) rre3(i4, m, 0) rre3(i3, m, 0) rre3(i2, m, 0) rre3(i1, m, 0) re(v, n)
                    
            if (F[i1][i2][i3][i4][i5][v]) {
                        
            if (i1) {
                            
            if (v == 1) tmp = i1 - 1else tmp = i1;
                            
            if (tmp) {
                                F[i1 
            - 1][i2][i3][i4][i5][0+= tmp * F[i1][i2][i3][i4][i5][v];
                                F[i1 
            - 1][i2][i3][i4][i5][0%= MOD;
                            }
                        }
                        
            if (i2) {
                            
            if (v == 2) tmp = i2 - 1else tmp = i2;
                            
            if (tmp) {
                                F[i1 
            + 1][i2 - 1][i3][i4][i5][1+= tmp * F[i1][i2][i3][i4][i5][v];
                                F[i1 
            + 1][i2 - 1][i3][i4][i5][1%= MOD;
                            }
                        }
                        
            if (i3) {
                            
            if (v == 3) tmp = i3 - 1else tmp = i3;
                            
            if (tmp) {
                                F[i1][i2 
            + 1][i3 - 1][i4][i5][2+= tmp * F[i1][i2][i3][i4][i5][v];
                                F[i1][i2 
            + 1][i3 - 1][i4][i5][2%= MOD;
                            }
                        }
                        
            if (i4) {
                            
            if (v == 4) tmp = i4 - 1else tmp = i4;
                            
            if (tmp) {
                                F[i1][i2][i3 
            + 1][i4 - 1][i5][3+= tmp * F[i1][i2][i3][i4][i5][v];
                                F[i1][i2][i3 
            + 1][i4 - 1][i5][3%= MOD;
                            }
                        }
                        
            if (i5) {
                            F[i1][i2][i3][i4 
            + 1][i5 - 1][4+= i5 * F[i1][i2][i3][i4][i5][v];
                            F[i1][i2][i3][i4 
            + 1][i5 - 1][4%= MOD;
                        }
                    }
                res 
            = F[0][0][0][0][0][0];
            }
            void pri()
            {
                cout 
            << res << endl;
            }
            int main()
            {
                init();
                solve();
                pri();
                
            return 0;
            }

            posted @ 2012-10-24 14:59 Mato_No1 閱讀(544) | 評論 (0)編輯 收藏

                 摘要: [SCOI2005]柵欄 [SCOI2005]騎士精神 DFS優化類題目的代表。【柵欄】方法一:將N塊目標木板的長度遞增排序,然后,從前到后搜索每塊目標木板從哪塊原料中得到,直到所有的原料都不夠用為止。優化:(1)啟發函數:從目前的每塊原料中,嘗試依次切出目前剩余的最小長度的目標木板,則各塊原料切出的塊數之和就是一個樂觀估計(比如剩余3塊原料的長度為10、12、19,剩余的目標木板為3、4、5、6...  閱讀全文

            posted @ 2012-10-19 21:48 Mato_No1 閱讀(1063) | 評論 (0)編輯 收藏

            相關鏈接
            插頭DP拯救了這個世界……

            趕快看插頭DP的論文去……
            (以后更新)

            posted @ 2012-10-19 21:48 Mato_No1 閱讀(398) | 評論 (0)編輯 收藏

            一開始想傻了囧……不過很快就發現這其實是個超級大水題……
            考慮斜堆中最后插入的那個結點,容易發現:
            (1)它一定是一個極左結點(就是從根往它的路上一直都是沿著左鏈走),因為插入的時候每次都是插入到左子樹中;
            (2)它一定木有右子樹,因為插入的時候每次都是把原來的某棵子樹作為新結點的左子樹;

            滿足(1)(2)的結點可能有多個,但緊接著可以發現,這個斜堆中的每個結點如果木有左子結點,那么也木有右子結點(或者說,每個非葉結點都有左子樹),而在插入一個結點之前,其所有的祖先都被交換了左右子樹,所以,若新結點的祖先中有滿足(1)(2)的,且新結點不是葉結點,那么在新結點插入之前,這個滿足(1)(2)的祖先必然是只有右子樹而木有左子樹的,這與上面的那個性質矛盾,所以,可以得出:最后插入的那個結點一定是滿足(1)(2)的結點中,深度最小的那個(設為X),除非X的左子結點是葉結點,此時為了滿足字典序最小,應該取X的左子結點為最后插入的。找到這個最后插入的結點以后,只需要把它刪掉,并把它的所有祖先交換左右子樹,就是插入該結點以前的狀態了。這樣可以找到字典序最小的插入順序。
            ———————————————————————————————————————————————————
            但是,這個題的意義還不止于此,必須要搞清楚斜堆到底是什么,有什么應用囧……

            斜堆是可合并堆的一種實現形式,其更穩定的實現是左偏樹(斜堆只能做到均攤logN,而左偏樹則可以嚴格做到每次操作O(logN))。
            斜堆最典型的特點,上面已經說過了,如果一個結點沒有左子樹,那么它也一定沒有右子樹。這樣,大多數斜堆看上去是往左傾斜的(這也就是它的名字的由來……)。如果給每個結點加上一個距離值dist[],為該結點到它最近的沒有右子樹的子結點的距離,并且滿足任意結點的左子結點的距離值都不小于右子結點的距離值的話,就成了左偏樹囧……

            可合并堆,顧名思義,它必須滿足兩個性質:(1)是堆,也就是每個結點的關鍵字都不大于(小頂堆)/不小于(大頂堆)其兩個子結點的關鍵字;(2)它必須在O(logN)時間內完成合并操作,即將兩個堆合并為一個,且合并成的堆仍滿足原來的性質。
            斜堆的合并操作有點像某些函數式數據結構,但它并不會動用額外的空間。該合并操作使用遞歸實現,設兩個斜堆(小頂堆)的根結點為A、B,若A和B中的某一個為空,則返回另一個;若A和B均非空,則先將它們中關鍵字小的那個的右子樹與關鍵字大的那個的整棵樹合并,作為關鍵字小的那個的新的右子樹,然后,如果是左偏樹的話要更新dist,若dist不滿足“左不小于右”,還要交換左右子樹。

            斜堆可以支持的操作有(指能在O(logN)時間內完成的操作):
            (1)插入結點:(用合并實現);
            (2)刪除任意結點:(將待刪除結點的兩棵子樹合并,取代原來的位置,若是左偏樹的話還要往上更新dist直到dist不變為止,某論文里有證明,每次刪除更新dist次數不會超過2logN);
            (3)合并兩個斜堆;
            (4)找最小/大值;
            (5)求以某個結點為根的子樹大小(維護sz即可);

            斜堆不能支持的操作有(指不能在O(logN)時間內完成的操作):
            (1)查找任意結點。因此,若要刪除某個指定結點,則必須先用下標等索引到它;
            (2)找第K小(如果這個都能實現的話,斜堆就可以替代平衡樹了囧……還是可合并平衡樹……);
            (3)找某個結點所在樹的根結點(但是配合并查集+索引可以實現,詳見HDU1512);

            至于編程復雜度方面……非常非常好寫!基本上一個合并操作就夠了,<10行(斜堆的好寫程度僅次于并查集和普通堆);
            寫的之后有三個主要的易疵點:
            (1)合并的時候別忘了更新一些東東,尤其別忘了返回根結點;
            (2)(極易疵的!!)如果要刪除某個結點,必須把它的所有信息恢復到孤立結點的狀態,即斷開與原樹的一切聯系(pr、L、R全部置0),dist(如果是左偏樹)置0、sz置1;(3)下標從1開始,0號結點作特殊用途(dist值為-1,sz值為0),如果某個結點的pr、L、R不存在則為0;

            例題(由于想穩定,本沙茶全都是用左偏樹寫的囧):
            【1】HDU1512
            基本操作題,配合并查集+索引找根即可;
            #include <iostream>
            #include 
            <stdio.h>
            #include 
            <stdlib.h>
            #include 
            <string.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 re2(i, l, r) for (int i=l; i<r; i++)
            #define re3(i, l, r) for (int i=l; i<=r; i++)
            #define rre(i, n) for (int i=n-1; i>=0; i--)
            #define rre1(i, n) for (int i=n; i>0; i--)
            #define rre2(i, r, l) for (int i=r-1; i>=l; i--)
            #define rre3(i, r, l) for (int i=r; i>=l; i--)
            #define ll long long
            const int MAXN = 100010, INF = ~0U >> 2;
            int n, u[MAXN], rt[MAXN], V[MAXN], dist[MAXN], pr[MAXN], L[MAXN], R[MAXN], res;
            int UFS_find(int x)
            {
                
            int tmp = x, r = x; while (u[r] >= 0) r = u[r]; while (x != r) {tmp = u[x]; u[x] = r; x = tmp;} return r;
            }
            void UFS_union(int s1, int s2, int rt0)
            {
                
            if (u[s1] >= u[s2]) {u[s1] = s2; u[s2]--; rt[s2] = rt0;} else {u[s2] = s1; u[s1]--; rt[s1] = rt0;}
            }
            int heap_union(int s1, int s2)
            {
                
            if (!s1) return s2; else if (!s2) return s1; else if (V[s1] >= V[s2]) {
                    
            int z = heap_union(R[s1], s2);
                    R[s1] 
            = z; pr[z] = s1; if (dist[L[s1]] < dist[z]) {int tmp = L[s1]; L[s1] = R[s1]; R[s1] = tmp;}
                    dist[s1] 
            = dist[R[s1]] + 1return s1;
                } 
            else {
                    
            int z = heap_union(s1, R[s2]);
                    R[s2] 
            = z; pr[z] = s2; if (dist[L[s2]] < dist[z]) {int tmp = L[s2]; L[s2] = R[s2]; R[s2] = tmp;}
                    dist[s2] 
            = dist[R[s2]] + 1return s2;
                }
            }
            void prepare()
            {
                dist[
            0= -1; re1(i, n) {u[i] = -1; rt[i] = i; dist[i] = pr[i] = L[i] = R[i] = 0;}
            }
            void solve(int x, int y)
            {
                
            int s1 = UFS_find(x), s2 = UFS_find(y); if (s1 == s2) {res = -1return;}
                
            int rt1 = rt[s1], rt2 = rt[s2];
                
            int z1 = heap_union(L[rt1], R[rt1]); L[rt1] = R[rt1] = pr[z1] = 0;
                V[rt1] 
            /= 2; z1 = heap_union(rt1, z1); pr[z1] = 0;
                
            int z2 = heap_union(L[rt2], R[rt2]); L[rt2] = R[rt2] = pr[z2] = 0;
                V[rt2] 
            /= 2; z2 = heap_union(rt2, z2); pr[z2] = 0;
                
            int z = heap_union(z1, z2); pr[z] = 0;
                UFS_union(s1, s2, z);
                res 
            = V[z];
            }
            int main()
            {
                
            int m, x0, y0;
                
            while (scanf("%d"&n) != EOF) {
                    re1(i, n) scanf(
            "%d"&V[i]); prepare();
                    scanf(
            "%d"&m);
                    re(i, m) {
                        scanf(
            "%d%d"&x0, &y0);
                        solve(x0, y0);
                        printf(
            "%d\n", res);
                    }
                }
                
            return 0;
            }


            【2】HDU3031
            綜合操作題,需要sz,同時也可以考察數據結構的綜合應用能力。
            #include <iostream>
            #include 
            <stdio.h>
            #include 
            <stdlib.h>
            #include 
            <string.h>
            #include 
            <algorithm>
            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 re2(i, l, r) for (int i=l; i<r; i++)
            #define re3(i, l, r) for (int i=l; i<=r; i++)
            #define rre(i, n) for (int i=n-1; i>=0; i--)
            #define rre1(i, n) for (int i=n; i>0; i--)
            #define rre2(i, r, l) for (int i=r-1; i>=l; i--)
            #define rre3(i, r, l) for (int i=r; i>=l; i--)
            #define ll long long
            const int MAXN = 1000010, MAXM = 101, MAXLEN_M = 10010, INF = ~0U >> 2;
            int n, m, len[MAXM], V0[MAXM][MAXLEN_M], root[2];
            int V[MAXN], dist[MAXN], pr[MAXN], L[MAXN], R[MAXN], sz[MAXN];
            bool FS;
            void upd(int x)
            {
                sz[x] 
            = sz[L[x]] + sz[R[x]] + 1;
            }
            int heap_union(int s1, int s2)
            {
                
            if (!s1) return s2; else if (!s2) return s1; else if (V[s1] >= V[s2]) {
                    
            int s0 = heap_union(R[s1], s2);
                    pr[s0] 
            = s1; R[s1] = s0; if (dist[L[s1]] < dist[s0]) {int tmp = L[s1]; L[s1] = R[s1]; R[s1] = tmp;} dist[s1] = dist[R[s1]] + 1; upd(s1);
                    
            return s1;
                } 
            else {
                    
            int s0 = heap_union(s1, R[s2]);
                    pr[s0] 
            = s2; R[s2] = s0; if (dist[L[s2]] < dist[s0]) {int tmp = L[s2]; L[s2] = R[s2]; R[s2] = tmp;} dist[s2] = dist[R[s2]] + 1; upd(s2);
                    
            return s2;
                }
            }
            void opr_T(int x)
            {
                sort(V0[x], V0[x] 
            + len[x]); int root0 = n + 1;
                rre(i, len[x]) {
                    n
            ++if (i == len[x] - 1) pr[n] = 0else pr[n] = n - 1if (i) L[n] = n + 1else L[n] = 0; R[n] = dist[n] = 0; V[n] = V0[x][i]; sz[n] = i + 1;
                }
                root[FS] 
            = heap_union(root[FS], root0);
            }
            void opr_A(int x)
            {
                V[root[FS]] 
            += x;
            }
            void opr_E(int x)
            {
                
            int root0 = root[FS], z0; pr[z0 = heap_union(L[root0], R[root0])] = 0; L[root0] = R[root0] = dist[root0] = 0; sz[root0] = 1; V[root0] = x;
                root[FS] 
            = heap_union(z0, root0);
            }
            void opr_L()
            {
                
            int root0 = root[FS], z0; pr[z0 = heap_union(L[root0], R[root0])] = 0; L[root0] = R[root0] = dist[root0] = 0; sz[root0] = 1;
            }
            void opr_C()
            {
                
            int root0 = root[0], root1 = root[1];
                
            if (V[root0] > V[root1]) {
                    root[
            0= heap_union(root0, root1); root[1= 0;
                } 
            else if (V[root0] < V[root1]) {
                    root[
            1= heap_union(root0, root1); root[0= 0;
                }
            }
            int main()
            {
                
            int tests, sc0 = 0, sc1 = 0, P, tmp; char ssss[10];
                scanf(
            "%d"&tests);
                re(testno, tests) {
                    scanf(
            "%d%d"&P, &m);
                    re(i, m) scanf(
            "%d"&len[i]);
                    re(i, m) re(j, len[i]) scanf(
            "%d"&V0[i][j]); n = root[0= root[1= 0; dist[0= -1; sz[0= 0; FS = 0;
                    re(i, P) {
                        scanf(
            "%s", ssss);
                        
            if (ssss[0== 'T') {scanf("%d"&tmp); opr_T(--tmp);}
                        
            else if (ssss[0== 'A') {scanf("%d"&tmp); opr_A(tmp);}
                        
            else if (ssss[0== 'E') {scanf("%d"&tmp); opr_E(tmp);}
                        
            else if (ssss[0== 'L') opr_L(); else opr_C();
                        FS 
            = !FS;
                    }
                    printf(
            "%d:%d\n", sz[root[0]], sz[root[1]]);
                    
            if (sz[root[0]] >= sz[root[1]]) sc0++else sc1++;
                }
                
            if (sc0 > sc1) puts("HahahaI win!!"); else puts("I will be back!!");
                
            return 0;
            }

            posted @ 2012-10-07 11:02 Mato_No1 閱讀(3054) | 評論 (1)編輯 收藏

            僅列出標題
            共12頁: 1 2 3 4 5 6 7 8 9 Last 
            久久久久久久综合日本| 一本色道久久综合狠狠躁| 精品久久久久久国产免费了| 久久久精品视频免费观看| 一本大道久久东京热无码AV| 精品久久久久久中文字幕人妻最新| 久久免费线看线看| 久久久久国产精品人妻| 国产高潮久久免费观看| 亚洲精品乱码久久久久久久久久久久 | 国产毛片欧美毛片久久久| 国产精品禁18久久久夂久| 午夜视频久久久久一区 | 中文字幕亚洲综合久久菠萝蜜| 久久久精品国产sm调教网站| 久久婷婷人人澡人人| 国产精品久久精品| 久久夜色精品国产欧美乱| 久久天天日天天操综合伊人av| 久久av无码专区亚洲av桃花岛| 欧美亚洲日本久久精品| 99精品伊人久久久大香线蕉| 久久久久亚洲AV成人片 | 久久噜噜电影你懂的| 蜜臀av性久久久久蜜臀aⅴ| 久久毛片一区二区| 欧美激情精品久久久久久久九九九| 国产成人久久精品区一区二区| 久久综合狠狠综合久久综合88| 久久这里都是精品| 一级女性全黄久久生活片免费 | 久久精品国产亚洲AV不卡| 国产精品久久国产精品99盘 | 国产69精品久久久久APP下载| 久久精品国产免费| www.久久热| 久久91亚洲人成电影网站| 久久免费视频观看| 国产精品亚洲综合专区片高清久久久 | 99久久无色码中文字幕人妻| 久久这里的只有是精品23|