• <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>
            posts - 43,  comments - 9,  trackbacks - 0
            void (*signal(int, void (*fp)(int)))(int); 
            Question:
            What is 'signal' ?
             
            #include <cstdio>
            using namespace std;

            void f(int);
            void (*pf)(int), (*qf)(int);
            void (*hf(intvoid(*)(int)))(int);

            typedef 
            void (*sighandler_t)(int);

            sighandler_t signal(
            int, sighandler_t);


            void f(int a) 
            {
                printf(
            "void f(int %d)\n", a);
            }


            void (*hf(int _i, void(*_pf)(int)))(int)
            {
                printf(
            "_i = %d\n", _i);
                _pf(_i);
                
            return _pf;
            }


            sighandler_t signal(
            int signum, sighandler_t sighandler)
            {
                printf(
            "signal num = %d\n", signum);
                sighandler(signum);
                
            return sighandler;
            }


            int main()
            {
                pf 
            = &f;
                qf 
            = hf(12, pf);
                qf(
            23);
                
                signal(
            54, f);
                
            return 0;
            }



            void (*signal(int, void (*)(int)))(int);
            Answer:
            signal is a function, passing {an int and a pointer [to a function passing an int returning nothing (void)]}, returning {a pointer [to a function passing an int returning nothing (void)]}.

            08合肥網(wǎng)賽某題。
            http://poj.org/problem?id=3697
            題意是問在N個(gè)點(diǎn)的完全圖(N<=10,000)中刪掉M(M<=1,000,000)條邊后, 還有多少個(gè)點(diǎn)與頂點(diǎn)1連通(頂點(diǎn)編號(hào)從1開始).
            暴力BFS+HASH+各種WS優(yōu)化的方法很多, 但是出題人原意應(yīng)該是O(M)的做法吧... 下面是我YY出來的O(M)的做法.

            只考慮這M條待刪邊, 能得到什么信息呢? 可以先從點(diǎn)1入手. 掃一遍與1鄰接的點(diǎn), 那么剩下沒被掃到的點(diǎn)肯定與1是連通的. 而被掃到的點(diǎn)是"有可能"與1不連通. 所以就把那些肯定與1連通的點(diǎn)做標(biāo)記. 從這些確定連通的點(diǎn)中任選一個(gè)u, 再掃描它的所有鄰接點(diǎn). 這之后, 如果一個(gè)點(diǎn)一共被掃了2次, 那么它才"有可能"與1不連通, 其它少于2次的點(diǎn)肯定與1連通, 因?yàn)樗蛘吲c1連通, 或者與u連通, 而u是已知與1連通的. 這樣再拿出一個(gè)已經(jīng)確定連通的點(diǎn), 掃描它的鄰接點(diǎn), 把被掃過次數(shù)<3的又標(biāo)記為已連通......

            經(jīng)過上面的YY, 算法基本上就出來了:
            把已知肯定與1連通的點(diǎn)集稱為S, 剩下不確定的為T. 一開始, S中只有1這一個(gè)點(diǎn), 其它點(diǎn)都在T中. 每個(gè)點(diǎn)有個(gè)計(jì)數(shù)器, 記錄自己被掃了多少次.
            1) 從S中取出一個(gè)沒處理過的點(diǎn), 把它標(biāo)記為已處理, 并遍歷它的所有鄰接點(diǎn), 被遍歷到的點(diǎn)的計(jì)數(shù)器都+1.
            2) T中所有"計(jì)數(shù)<S中已處理點(diǎn)個(gè)數(shù)"的, 都可以確定是連通的, 把它們從T中刪除, 加入S中.
            3) 重復(fù)1), 直到S中所有點(diǎn)都處理完.
            這時(shí), S中的點(diǎn)就是與1連通的, T中剩下的就是不連通的.

            復(fù)雜度分析:
            讀入邊和掃描邊都是O(M)的.
            S集可以用隊(duì)列維護(hù), 總共O(N).
            T集的維護(hù): 每一輪都要掃一遍當(dāng)前的T, 把所有計(jì)數(shù)小的刪掉, 放進(jìn)S中. 這樣, 這一步的總復(fù)雜度就是O(sigma(T)), 會(huì)不會(huì)到達(dá)O(N^2)呢? 實(shí)際上是不會(huì)的. 因?yàn)橐粭l邊最多只會(huì)使一個(gè)頂點(diǎn)的計(jì)數(shù)+1, 因此每一輪還剩在T中的點(diǎn)數(shù)不會(huì)超過這一輪遍歷過的邊數(shù). 這樣, 所有回合的sigma(T)就肯定不會(huì)超過總邊數(shù). 因此這里總共也是O(M)的. 嚴(yán)格來說算上第1輪有N-1個(gè)點(diǎn), 也是O(M+N).
            這樣總的復(fù)雜度就是O(M)了.

            不過這個(gè)算法讀入用scanf時(shí), g++跑了1000+ms, 改成getchar才到200+ms的. 不知道排前面的神們是不是有更NB的算法.

            代碼:
             1 #include 
             2 #include 
             3 #include 
             4 #include 
             5 #include 
             6 using namespace std;
             7 
             8 const int MAXN = 10010;
             9 const int MAXM = 1000010;
            10 
            11 struct Edge {
            12     int v, next;
            13 }edg[MAXM*2];
            14 int ecnt, gg[MAXN];
            15 bool yes[MAXN];
            16 int que[MAXN], pq, sq, cnt[MAXN], vt[MAXN], nt;
            17 int N, M;
            18 
            19 inline int getnextint()
            20 {
            21     int r = 0;
            22     char c;
            23     while(!isdigit(c=getchar())); 
            24     do{
            25         r = r*10 + c-'0';
            26     } while(isdigit(c=getchar()));
            27     return r;
            28 }
            29 
            30 inline void addedge(int u , int v)
            31 {
            32     edg[ecnt].v = v; edg[ecnt].next = gg[u], gg[u] = ecnt++;
            33     edg[ecnt].v = u; edg[ecnt].next = gg[v], gg[v] = ecnt++;
            34 }
            35 
            36 int main()
            37 {
            38     int cas = 0;
            39     while(~scanf("%d%d"&N, &M) && !(N==0 && M==0)){
            40         
            41         ecnt = 0;
            42         for(int i = 0; i < N; i++){
            43             gg[i] = -1;
            44             yes[i] = i==0 ? true : false;
            45             cnt[i] = 0;
            46             vt[i] = i+1;
            47         }
            48         nt = N-1;
            49         
            50         for(int i = 0; i < M; i++){
            51             int u = getnextint();
            52             int v = getnextint();
            53             addedge(--u, --v);
            54         }
            55         
            56         pq = sq = 0;
            57         que[sq++= 0;
            58         yes[0= true;
            59         
            60         while(pq != sq) {
            61             int u = que[pq++];
            62             for(int e = gg[u]; e >= 0; e = edg[e].next) {
            63                 if(!yes[edg[e].v])
            64                     cnt[edg[e].v]++;
            65             }
            66             for(int i = 0; i < nt; i++) {
            67                 while(i < nt && cnt[vt[i]] < pq) {
            68                     yes[vt[i]] = true;
            69                     que[sq++= vt[i];
            70                     if(i < --nt) 
            71                         vt[i] = vt[nt];
            72                 }
            73             }
            74         }
            75         printf("Case %d: %d\n"++cas, sq-1);
            76         
            77     }
            78     return 0;
            79 }
            250pt MagicalGirlLevelOneDivOne
            某神在(0,0)處, 需要走到(x,y)處(0<x,y<=10^9), 他只能按類似馬跳的方式走, 即, 給出一個(gè)n, 他可以從(a,b)走到(a-1,b-n) (a+1,b-n) (a-1,b+n) (a+1,b+n) (a-n,b-1) (a+n,b-1) (a-n,b+1) (a+n, b+1) 中的一個(gè).現(xiàn)在給出50個(gè)不同的n[1..50], 他可以以任意的n[i]方式走, 每種方式的使用次數(shù)不限. 問能否走到目的地(x,y).

            很明顯, 此神可以沿任意方向2步2步的走, 即先走個(gè)(+1,-n), 再走個(gè)(+1,+n). 所以能否到終點(diǎn), 只與奇偶性有關(guān). 
            經(jīng)過一陣分類討論可知:
            1) 如果x+y=0(mod 2), 則YES. 
            2) 如果x+y=1(mod 2), 且n[i]中有偶數(shù), 則YES.
            3) 否則NO.

            [雜]

            600pt MagicalGirlLevelTwoDivOne
            給一個(gè)H*W(1<=H,W<=50)的矩陣A, 每一位上已經(jīng)有一個(gè)1~9的數(shù)字, 或者是個(gè)'.', 在'.'處可以填上任意1~9的數(shù)字. 再給出n和m(1<=n<=min{10,H}, 1<=m<=min{10,W}). 問一共有多少種填'?'的方法, 使得整個(gè)矩陣滿足:
            對(duì)任意的r和c, 以(r,c)開始的水平方向上連續(xù)m個(gè)數(shù)之和是奇數(shù);
            對(duì)任意的r和c, 以(r,c)開始的垂直方向上連續(xù)n個(gè)數(shù)之和是奇數(shù).

            首先要注意到一個(gè)性質(zhì): 對(duì)任意r和c有 A[r,c]與A[r+n,c]的奇偶性相同. 很顯然, 因?yàn)橐獫M足A[r,c]+A[r+1,c]+...+A[r+n-1,c]與A[r+1,c]+...+A[r+n-1,c]+A[r+n,c]的奇偶性相同, 都是奇數(shù). 列上同樣有A[r,c]與A[r,c+m]奇偶性相同.
            因此在一行上, 只用記錄n位的奇偶狀態(tài), 列上同理. 這樣,所有的(r+pn,c+qm)都能合并成同一個(gè)點(diǎn), 且只有兩種狀態(tài): 奇和偶. 合并后該點(diǎn)為奇(或偶)的方法數(shù), 等于組成它的所有點(diǎn)方法數(shù)之積. 最后整個(gè)矩陣合并壓縮成一個(gè)n*m的矩陣, 就可以用狀態(tài)DP來搞, 求每行每列之和都為奇的方法數(shù). dp[n][1<<m], 前n行, 每一列和的奇偶性對(duì)應(yīng)bit為0或1. O(1<<m)的轉(zhuǎn)移復(fù)雜度, 轉(zhuǎn)移時(shí)要注意該行狀態(tài)1有奇數(shù)個(gè).

            覺得是道很好的題, 狀態(tài)設(shè)計(jì)很巧妙...

            [狀態(tài)DP 狀態(tài)壓縮設(shè)計(jì)]

            900pt MagicalGirlLevelThreeDivOne
            某神給出K(K<=50)個(gè)01串, 每個(gè)串的長度不超過50. 用這些串組成新的串放到數(shù)組A[]里. 如果i<K, 則A[i]為給出的第i個(gè)串. 否則A[i] = A[i-1] + A[i-K-1] + A[i-2*K-1] + ... + A[i-p*K-1], 其中p是使i-p*K-1>=0的最大整數(shù). 現(xiàn)在此神給出n, lo, hi, 要你求A[n]的子串A[n][lo...hi]中有多少個(gè)連續(xù)的1. 0<=n<=10^15, 0<=hi<= min{A[n]的長度, 10^15}, 0<=lo<=hi. 所有計(jì)數(shù)以0開始.

            首先隨便打個(gè)表或者手推一下化簡A[i]的遞推式, 可以發(fā)現(xiàn)當(dāng)i>=2*K時(shí), A[i] = A[i-1] + (A[i-K-1] + ... A[i-p*K-1]) = A[i-1] + A[i-K], 而K<=50. 所以A[i]的長度關(guān)于i是指數(shù)增長的, 50log(10^15)可能夠用(嚴(yán)格證明不太會(huì), 求指導(dǎo)#.#). 因此其實(shí)n<=10^15范圍是坑爹的, hi不會(huì)超過A[10^4]的長度. 而這些串的前綴都是一樣的, 所以A[n][lo..hi]其實(shí)與A[10^4][lo..hi]相同.
            這樣便可直接利用A[i] = A[i-1] + A[i-K]的關(guān)系分治. 和用線段樹求最長連續(xù)1串的思想差不多: 每個(gè)結(jié)點(diǎn)的狀態(tài)變量是(id,lo,hi), 存放A[id][lo..hi]的最優(yōu)解. 除了存放當(dāng)前段的最大長度max外, 為了能合并子區(qū)間, 還要記錄當(dāng)前區(qū)間從左端開始連續(xù)1的個(gè)數(shù)sl, 和從右端開始連續(xù)1的個(gè)數(shù)sr. 剩下的工作與線段樹無異, 假設(shè)要求(id, lo, hi)的(max, sl, sr):
            對(duì)于A[id], 它的左兒子就是A[id-1], 右兒子是A[id-K].
            1)如果id<2*K, 直接暴力.
            2)如果lo>=len[id-1](類似于線段樹中的查詢區(qū)間完全落在右兒子), 則遞歸查詢(id-K, lo-len[id-1], hi-len[id-1]).
            3)如果hi<len[id-1], 則遞歸查詢(id-1, lo, hi).
            4)否則兩個(gè)兒子都要查詢, 并根據(jù)返回的結(jié)果求當(dāng)前區(qū)間的結(jié)果.

            分治思想很強(qiáng)大, 用map寫的"線段樹"很YD, 偶依然蒻爆了.

            [分治 復(fù)雜度分析]

            500pt Perfect Memory
            題意: 某神在M*N(1<=M, N<=50, M*N為偶數(shù))的格子上玩對(duì)對(duì)碰: 每個(gè)格子都有個(gè)隱藏的圖形. 此神一次行動(dòng)翻開2個(gè), 如果相同, 就成功消去這2個(gè)格子. 如果不相同, 那這2個(gè)格子又恢復(fù)隱藏狀態(tài). 但是此神記憶力很NB, 能記住所有翻開過的格子是什么圖形. 還有重要的一點(diǎn), 他一次行動(dòng)時(shí), 是先翻開1個(gè)格子, 知道它的圖形之后, 再?zèng)Q定怎么翻第2個(gè)格子, 而不是兩個(gè)格子同時(shí)翻開. 問此神把所有格子都消去, 需要消耗的行動(dòng)次數(shù)的期望.

            容易想到期望與翻格子的位置無關(guān). 有關(guān)的量是: 當(dāng)前還有多少對(duì)圖形沒被消去. 其中有多少對(duì)圖形已經(jīng)知道其中一個(gè)的位置了. so, dp[i][j], i為前者, j為后者. 一次行動(dòng)中, 第1個(gè)格子肯定翻之前沒翻過的(一共有2i-j個(gè), 記為s), 除非已經(jīng)知道某1對(duì)的位置, 直接把2個(gè)都翻出來消掉. 所以轉(zhuǎn)移有幾種情況:
            1) 從s中翻出1個(gè)新圖形. 從剩下s-1中翻出了相同圖形, 消除. 這樣的概率是2(i-j)/s * 1/(s-1), 轉(zhuǎn)移到dp[i-1][j].
            2) 從s中翻出1個(gè)新圖形. 從剩下s-1中又翻出新圖形, 這樣就多了2種已知圖形. 概率是2(i-j)/s * 2(i-j-1)/(s-1), 轉(zhuǎn)移到dp[i][j+2].
            3) 從s中翻出1個(gè)新圖形. 從剩下s-1中翻出了之前j個(gè)已知圖形中的一個(gè). 這樣, 下一次就可以消耗一次行動(dòng)把那對(duì)已知圖形消去, 轉(zhuǎn)移到dp[i-1][j], 概率是2(i-j)/s * j/(s-1).
            4) 從s中翻出1個(gè)已知圖形. 直接翻出與它配對(duì)的消去. 轉(zhuǎn)移到dp[i-1][j-1], 概率是j/s * 1.

            所以 dp[i][j] = p1*(dp[i-1][j]+1) + p2*(dp[i][j+2]+1) + p3*(dp[i-1][j]+2) + p4*(dp[i-1][j-1]+1).
            其中2)的條件是i>=j+2, 4)的條件j>=1. 邊界dp[i][i] = i. 最后dp[M*N][0]即為所求.

            [概率 期望 DP]

            1000pt Reflections
            題意: 某神在三維空間中玩一個(gè)游戲, 空間中有N個(gè)(N<=20)平面, 每個(gè)平面都垂直于某個(gè)坐標(biāo)軸, 并且與該坐標(biāo)軸交于整點(diǎn). 此神從(0,0,0)處出發(fā), 想去(X,Y,Z)處. 現(xiàn)在他每行動(dòng)一次可以做如下移動(dòng):
            1) 走到與他相鄰的1個(gè)整點(diǎn)上, 即(x+1, y, z) (x-1, y, z) (x, y+1, z) (x, y-1, z) (x, y, z+1) (x, y, z-1)中的一個(gè).
            2) 神一次行動(dòng)可以利用一個(gè)平面, 移動(dòng)到關(guān)于這個(gè)平面對(duì)稱的點(diǎn)處. 每個(gè)平面在整個(gè)游戲過程中至多只能利用一次.
            問此神到達(dá)終點(diǎn)花費(fèi)的最少行動(dòng)次數(shù).

            易知三個(gè)方向是不相關(guān)的. 所以只用先考慮一維的情形.
            首先要想到, 走路和反射交替, 是等效于先反射完了再一口氣走到終點(diǎn)的. 因?yàn)樵诜瓷渲暗淖邉?dòng), 不會(huì)被反射動(dòng)作放大. 反射前移動(dòng)多少步, 經(jīng)過若干次反射后所到達(dá)的位置, 與不移動(dòng)直接反射到達(dá)的位置, 相差正好是移動(dòng)的步數(shù).
            所以可以轉(zhuǎn)化為先反射若干次, 再行走到終點(diǎn). 現(xiàn)在就要推出反射到達(dá)的位置公式.
            假設(shè)每個(gè)反射軸的坐標(biāo)依次是x[1], x[2], ..., x[n], 神經(jīng)過第k次反射后的位置是p[k].
            容易推出, p[1] = 2x[1], p[2] = p[1] + 2(x[2]-x[1]) = 2x[2] - 2x[1], ... p[k] = 2x[k]-2x[k-1]+2x[k-2]-...+2*(-1)^(k-1)x[1].
            這是很規(guī)則的正負(fù)交替求和, 正項(xiàng)數(shù)等于負(fù)項(xiàng)數(shù), 或者比負(fù)項(xiàng)數(shù)多1.
            到此問題轉(zhuǎn)化得很清晰了: 在20個(gè)數(shù)中選出k個(gè)數(shù)作為正項(xiàng), k(或k-1)個(gè)數(shù)作為負(fù)項(xiàng), 每個(gè)數(shù)至多被選1次. 該方案的總行動(dòng)次數(shù)是選出的個(gè)數(shù)(即做反射的總次數(shù)), 加上這些項(xiàng)之和到終點(diǎn)的距離(即最后一路走過去). 
            選數(shù)要降低復(fù)雜度, 可以把20個(gè)數(shù)分成兩個(gè)集合, 每邊10個(gè)數(shù), 先各自生成2^10個(gè)和. 兩邊分別排序后, 從小到大枚舉左邊的, 記一個(gè)指針從大到小掃右邊的.

            [數(shù)學(xué) 分治]
            本文純屬YY……

            今天多校聯(lián)合訓(xùn)練三的C題,http://acm.hdu.edu.cn/showproblem.php?pid=3861,題意歸結(jié)起來是在一個(gè)有向圖中求最小路徑覆蓋,也就是用盡量少的鏈去覆蓋整個(gè)圖,每個(gè)頂點(diǎn)必須屬于且只能屬于一條鏈。但是題意并未說明原圖無環(huán)。標(biāo)程解法是強(qiáng)連通分量縮點(diǎn),再求有向無環(huán)圖的最小路徑覆蓋。反例是:1->2,2->3,4->5,5->6,2->5,5->2。正解是2,123一組,456一組。

            因?yàn)槭且舐窂綌?shù)最小,所以YY了一個(gè)上下界最小流的做法。構(gòu)圖是將原來的點(diǎn)A0拆成兩個(gè),A和A'。從A到A'連一條邊,下界和上界都為1。所有原來A0的出邊,都從A'出去,下界0,上界1.所有原來A0的入邊,都指向A。新建一個(gè)源點(diǎn)S,一個(gè)匯點(diǎn)T。從S到每個(gè)點(diǎn)A連一條邊,下界0,上界1。從每個(gè)A'到T連一條邊,下界0,上界1。

            對(duì)這個(gè)新圖求最小流,即為原題所求。

            YY的證明:
            A->A',限制了這個(gè)點(diǎn)必須經(jīng)過一次。這條邊上的流量有兩個(gè)來源:其它的點(diǎn)B',或者源點(diǎn)S,前者說明A和B在同一條鏈中,B是A的前驅(qū),后者說明A是鏈的起點(diǎn)。同樣,這個(gè)流量有兩個(gè)去處:其它的點(diǎn)C',或者匯點(diǎn)T,前者說明A和C在同一條鏈中,C是A的后繼,后者說明A是鏈的終點(diǎn)。

            到達(dá)匯的每1單位流量,意味著一條鏈的終結(jié)。所以最小流就能讓鏈數(shù)最少。

            YY完畢,歡迎開炮……


            ps. 理論上說,以上方法肯定是錯(cuò)的。要不然求Hamiltion通路就不是NP了@。@
            500pt FiveHundredEleven
            給出N(N<=50)個(gè)不小于0且不大于511的整數(shù). 開始時(shí)寄存器為0, 兩人輪流選取一個(gè)數(shù), 與寄存器的值OR, 把結(jié)果覆蓋寫入寄存器. 數(shù)不能重復(fù)使用. 如果某人操作之后寄存器的值為511, 或者輪到某人時(shí)數(shù)都取完了, 那么這個(gè)人就算負(fù). 問先手是否有必勝策略.
            容易想到2^9這一維, 記錄當(dāng)前每一位的0/1狀態(tài). 實(shí)際上, 不需要記錄當(dāng)前已經(jīng)選過哪些數(shù), 而只用記錄已經(jīng)選了幾個(gè)數(shù), 再由當(dāng)前的0/1態(tài), 就能推算出哪些數(shù)沒選過. 有些數(shù)x滿足x|now != x, 這些數(shù)肯定沒選過. 而對(duì)那些x|now == x的數(shù), 不必知道它具體的值, 因?yàn)樗鼘?duì)后續(xù)操作的影響都一樣, 就是延緩一步, 把局面原封不動(dòng)地丟給對(duì)方. 所以只需知道當(dāng)前還有多少個(gè)這樣的x沒被使用過, 這個(gè)值也能由上面的信息得到.
            這樣就是一個(gè)類似極大極小的必勝必?cái)B(tài)記憶化搜索.
            狀態(tài)為dp[1<<9][N], 轉(zhuǎn)移為N.

            [狀態(tài)DP]

            1000pt GameOfLifeDivOne
            一個(gè)長為N(N<=50)的串(環(huán)狀, 首尾相連, 即x[N-1]與x[0]相連), 由'0', '1' 和'?'組成, 其中'?' 處可以填上'0'或'1'. 從T=0開始, 每過1單位時(shí)間, 整個(gè)串會(huì)更新一次: 某一位, 如果上一時(shí)刻, 它, 以及與它相鄰的兩位, 一共有至少2個(gè)'1', 那么這一時(shí)刻它變成'1', 否則它變成'0'. 問共有多少種填'?'的方法, 使得在經(jīng)過T(T<=1000)時(shí)間后, 還有不少于K(K<=N)個(gè)'1'. 比如'101010'->'010101'->'101010'->...; '11010'->'11101'->'11111'->...

            首先容易觀察到, 兩個(gè)或兩個(gè)以上連續(xù)相同的位是永遠(yuǎn)不會(huì)變的. 只有01交替的子串才會(huì)發(fā)生變化. 所以任意一個(gè)串都可以看成是若干個(gè)形如 xpy的子串首尾連接而成, 而且兩串的首尾要相同才能連起來, 就像[xp1y][yp2x][xp3x][xp4y].... 其中pk是01交替序列, x和y都是一位, 可能是'0'或'1'. 特別的,連續(xù)3個(gè)相同字符可以看成是xx和xx粘起來(有1位重疊). 對(duì)于一個(gè)首尾字符固定不變的01交替串, 它在T時(shí)間后有多少個(gè)'1'是很容易算的. 兩頭都是0的話, 如0101010->0010100->0001000, 每時(shí)間減少一個(gè)1; 兩頭都是1的話類似, 每時(shí)間增加一個(gè)1. 一頭是0一頭1, 則0和1的個(gè)數(shù)都不變, 如010101->001011->000111. 
            這樣就有個(gè)算法的雛形, 類似背包: dp[pos][bit][one]表示: 從0到pos-1的子段, 以bit結(jié)尾, 且T時(shí)間后包含one個(gè)1的方法數(shù). 如果從pos到某一位pos2-1, 能構(gòu)造出以bit起始, 以bit2結(jié)束的交替串, 那么從狀態(tài)dp[pos][bit][one]就能擴(kuò)展到dp[pos2][bit2][one+one2], 則把前者加到后者上去, 其中one2是pos到pos2-1這個(gè)子串T時(shí)間后1的個(gè)數(shù). 把原始串復(fù)制兩遍, 就能比較方便地處理環(huán). 
            枚舉在原串中首次出現(xiàn)連續(xù)2個(gè)相同字符的位置startpos, 對(duì)每個(gè)startpos做一次上述DP. 把所有one>=K的方法數(shù)加起來即可. 此外要先預(yù)處理出任意edg[i][b1][j][b2], 即從i到j(luò)-1能否構(gòu)造出以b1開始, b2結(jié)尾的交替串, 如果能, T時(shí)間后有多少個(gè)'1'. 
            其實(shí)整個(gè)題就是一道背包DP, 求用若干個(gè)短棍子, 拼出一個(gè)權(quán)值>=K的長棍子的方法數(shù). 只是模型隱藏得很巧妙. orz...

            [背包DP]

            250p CubeStickers
            給出若干個(gè)方形木板,每個(gè)木板有一種顏色。現(xiàn)在要選出其中6個(gè),圍出一個(gè)立方體。問是否可能使轉(zhuǎn)出的立方體,任意兩個(gè)相鄰的面顏色不同。
            直接按木板的總數(shù)分情況討論就可以,但是我漏想了一種情況@.@
            其實(shí)顯然,同一種顏色最多能用兩次,所以統(tǒng)計(jì)每種木板能用的個(gè)數(shù)之和,sigma(min(count[i],2)),和不小于6則可行。

            500p CubePacking
            給出Ns個(gè)邊長為1的立方體和Nb個(gè)邊長為L(2<=L<=10)的立方體。要找一個(gè)體積最小的長方體,使得可以把所有立方體堆進(jìn)去。保證結(jié)果不超int32。
            正是因?yàn)椴怀琲nt32,所以可以直接枚舉兩條棱x,y,算第3條z的最小值。枚舉時(shí)循環(huán)條件 x*x*x <= INF, x*y*y <= INF。計(jì)算z的最小值時(shí)要注意除法要向上取整,而且判斷能否把邊長為L的立方體都放進(jìn)去的條件是(x/L)*(y/L)*(z/L) >= Nb,如果z小了,要加到足夠大為止。
            [枚舉]

            900p CubeBuilding
            大小相同的紅、綠、藍(lán)色的立方體,分別給R、G、B個(gè)(R,G,B<=25)。把這些立方體全部搭積木一樣的堆到N*N(N<=25)的格子棋盤中。可以在任意格子中堆任意高的立方體。規(guī)定一種方案是合法的,如果從北向南看的側(cè)視圖中只有一種顏色。問一共有多少種堆砌的方案。
            可以先考慮N*1的棋盤,也就是側(cè)視圖中棋盤寬度是1。先考慮沒有顏色的方塊怎么放,再去染色。這樣不管怎么堆,看到的方塊數(shù)總是等于所有格子堆的最大高度,則需要固定顏色的方塊數(shù)就為這個(gè)高度,剩下的方塊可以任意染色。同理N*N的棋盤,需要固定顏色的方塊數(shù)等于所有列中需要固定的數(shù)量之和。要求的答案就是,先枚舉固定方塊的數(shù)目,把它們?nèi)灸骋环N顏色,剩下的方塊可以用組合數(shù)直接算出有多少種染色方案,乘起來,最后求和。
            關(guān)鍵就是要求出每一種固定方塊數(shù)目的前提下,不考慮顏色,有多少種堆放方法。
            由前面的討論知道,可以先在N*1的棋盤上按行擴(kuò)展,需要記錄的狀態(tài)是當(dāng)前已使用的方塊數(shù),當(dāng)前的最大高度。
            然后利用這個(gè)結(jié)果按列擴(kuò)展,記錄的狀態(tài)是當(dāng)前已使用的方塊數(shù),當(dāng)前已固定的方塊數(shù)。
            ps.染色之前的方案數(shù)只用求一次,之后分別把固定的方塊染成3種不同顏色,只要用組合數(shù)分別算3次,加起來就行了。
            O(9*N^5)的算法,時(shí)限有點(diǎn)緊。
            [DP]
            500pt
            50個(gè)點(diǎn)的地圖,從0開始按照順序訪問一系列點(diǎn)(不超過50個(gè)),訪問順序給出,一個(gè)點(diǎn)可能訪問多次。某些點(diǎn)停著若干輛汽車。可以走路,也可以開車。開車的速度比走路快。但是限定一輛汽車只能使用一次,也就是下車后這輛車就作廢。問按要求訪問完所有點(diǎn)的最短總耗時(shí)。 先floyd求每對(duì)點(diǎn)之間走路時(shí)間和開車時(shí)間。對(duì)于訪問順序中的每一步,使用每輛車都有個(gè)節(jié)省的時(shí)間。這就相當(dāng)于建個(gè)二分圖,左邊x是訪問順序中的每一步,右邊y是每一輛車。xi與yj的邊權(quán)就是第i步使用第j輛車能節(jié)省的時(shí)間。 最后結(jié)果就是總的走路時(shí)間減去最大權(quán)匹配。

            [floyd最短路 二分圖最大權(quán)匹配]
            250p TheMoviesLevelOneDivOne
            電影院有n行m列的座位, 有一些已經(jīng)被預(yù)訂了. 求在剩下的座位中, 選出同行且相鄰的兩個(gè)座位的方案數(shù).
            可以按行列將已預(yù)訂的座位排序, 然后順便掃一遍, 算出相鄰兩個(gè)被預(yù)訂座位之間的方案數(shù). 最后累加.
            也可以用個(gè)set記錄不能使用的方案, 再用沒有預(yù)訂座位的情況下的總方案數(shù)減去之.

            500p TheMoviesLevelTwoDivOne
            若干部電影, 每部電影有一個(gè)加血的時(shí)間點(diǎn). 人看電影, 每看一分鐘掉一點(diǎn)血. 血掉到0就結(jié)束. 問怎樣按排順序使看的電影部數(shù)最多. 如果總部數(shù)相同, 取字典序最小的解輸出.
            只有20部電影, 狀態(tài)DP即可.
            為保證字典序, 可以從后往前DP, 這樣每次轉(zhuǎn)移時(shí)新加入的電影都是當(dāng)前最先看的, 保證它先擇的是最小的, 即能保證字典序最小.

            [DP]

            1000p TheMoviesLevelThreeDivOne
            若干部電影, A和B兩人看每部電影的時(shí)間分別是A[i], B[i]. 初始安排, 要依次把第1,2,..,n部電影放入A或B的待看隊(duì)列的隊(duì)尾. A和B各自開始看自己隊(duì)列中的電影, 看完一部后, 如果這是另一個(gè)人沒看過的, 就加入它的隊(duì)列中. 如果期間某人列隊(duì)空了, 那么他就結(jié)束, 再也不看新電影了. 問有多少種初始安排方法, 能使A和B都能看完所有電影.
            首先肯定不會(huì)出現(xiàn)一種安排使得A和B都卡. 因?yàn)锳卡肯定發(fā)生在A看完他所有的電影之后, 且此時(shí)B沒看完自己的, 所以B肯定不會(huì)卡.
            這樣就可以用總方案數(shù)2^N分別減去A卡的和B卡的方案數(shù). 考慮A卡的情況. 假設(shè)A那一整坨東西的時(shí)長是sumA, B的第一個(gè)東西是tb1, 則A卡的條件是 sumA-tb1<0. 否則B看完tb1后把ta1加在sumA后面, 這時(shí)卡的條件是(sumA+ta1)-(tb1+tb2)<0. 依此, 如果在這過程中任意一次卡的條件符合, 那么后續(xù)怎么安排都是卡的. 于是用一維狀態(tài)記錄目前為止出現(xiàn)過的最小的X-Y, min, 還要一維記錄當(dāng)前的X-Y, cur, 以轉(zhuǎn)移用. 轉(zhuǎn)移時(shí), 如果把當(dāng)前電影放進(jìn)A, 那么min和cur都增加A[i], 因?yàn)閟umA增加了. 如果放進(jìn)B, 那么用cur和B[i]來計(jì)算新的cur和min.
            hint. cur=當(dāng)前所有電影的A[i]的和-B中電影的B[i]的和, 新的min=除了新放的電影外所有放過的電影的A[i]的和-包括新電影在內(nèi)的B中電影的B[i]的和.

            ps. 1000的DP都很YD啊...

            [DP]
            僅列出標(biāo)題  下一頁
            <2025年7月>
            293012345
            6789101112
            13141516171819
            20212223242526
            272829303112
            3456789

            "Do not spend all your time on training or studying - this way you will probably become very exhausted and unwilling to compete more. Whatever you do - have fun. Once you find programming is no fun anymore – drop it. Play soccer, find a girlfriend, study something not related to programming, just live a life - programming contests are only programming contests, and nothing more. Don't let them become your life - for your life is much more interesting and colorful." -- Petr

            留言簿(3)

            隨筆分類(59)

            隨筆檔案(43)

            cows

            搜索

            •  

            最新評(píng)論

            評(píng)論排行榜

            久久青青草原精品影院| 久久这里只有精品18| 亚洲乱亚洲乱淫久久| 国产精品久久久久乳精品爆 | 中文精品久久久久人妻| 狠狠色丁香久久婷婷综合蜜芽五月 | 久久久久这里只有精品 | A级毛片无码久久精品免费| 久久性生大片免费观看性| 欧洲成人午夜精品无码区久久| 国产精品久久久久aaaa| 久久婷婷是五月综合色狠狠| 亚洲午夜精品久久久久久人妖| 亚洲中文字幕伊人久久无码| 日本福利片国产午夜久久| 狠狠色丁香久久婷婷综合_中| 久久综合九色综合久99| 久久人人爽人人人人片av| 久久久久国产精品三级网| 人人狠狠综合久久亚洲婷婷| 亚洲中文久久精品无码| 理论片午午伦夜理片久久| 91精品久久久久久无码| 国产午夜精品久久久久免费视| 欧美日韩精品久久久久| 一本综合久久国产二区| 久久国产成人精品国产成人亚洲| 国产午夜久久影院| 72种姿势欧美久久久久大黄蕉| 少妇高潮惨叫久久久久久| 少妇熟女久久综合网色欲| 亚洲国产成人精品久久久国产成人一区二区三区综 | 九九久久精品国产| 精品综合久久久久久97超人| 少妇高潮惨叫久久久久久| 午夜精品久久久久久久| 一本久久a久久精品vr综合| 中文无码久久精品| 国产情侣久久久久aⅴ免费| AAA级久久久精品无码片| 成人久久久观看免费毛片|