• <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>
            最近做了兩道LIS模型題,感覺到模型比較好,總結一下囧。
            【1】[HAOI2007]上升序列
            預處理:設F[i]為以i開頭的最長上升序列的長度,怎么求不用說了吧囧……
            假設目前需要求長度為M的、標號字典序最小的上升序列,顯然其第一個元素A[i]必須滿足F[i]>=M(注意,不是等于,是大于等于!),找到滿足這個條件的最小的i即可。然后,設目前已經求出了該序列的第x個元素為A[y],則第(x+1)個元素A[z]需要滿足的條件是A[z]>A[y],且F[z]=F[y]-1,找到滿足這個條件的最小的z即為該序列的第(x+1)個元素。按照這種方法,掃描一遍就可以求出整個序列,時間復雜度為O(N)。如果整個序列的最長上升序列長度<M,則無解。

            代碼:
            #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 = 10010,    MAXM = 1010, INF = ~0U >> 2;
            int n, m, len, A[MAXN], F[MAXN], D[MAXN], res[MAXM];
            void prepare()
            {
                D[len 
            = 0= INF; int l, r, mid;
                rre(i, n) 
            if (A[i] < D[len]) D[F[i] = ++len] = A[i]; else {
                    l 
            = 0; r = len;
                    
            while (l < r) {
                        mid 
            = l + r + 1 >> 1;
                        
            if (A[i] < D[mid]) l = mid; else r = mid - 1;
                    }
                    F[i] 
            = l + 1; D[l + 1= A[i];
                }
            }
            void solve()
            {
                
            int x, y;
                re(i, n) 
            if (F[i] >= m) {
                    res[
            0= A[i]; if (m == 1return; x = m - 1; y = 1;
                    re2(j, i
            +1, n) if (F[j] >= x && A[j] > res[y - 1]) {res[y++= A[j]; if (y == m) returnelse x--;}
                }
            }
            int main()
            {
                scanf(
            "%d"&n); re(i, n) scanf("%d"&A[i]);
                prepare();
                
            int m_s; scanf("%d"&m_s);
                re(i, m_s) {scanf(
            "%d"&m); if (m > len) puts("Impossible"); else {solve(); re(j, m-1) printf("%d ", res[j]); printf("%d\n", res[m - 1]);}}
                
            return 0;
            }


            【2】[HAOI2006]數字序列
            首先,由于序列的所有元素都是整數,所以可以將原序列的所有元素減去它的下標,這樣就把上升序列轉化為不下降序列了。
            第一問的結果顯然就是(N-新序列的最長不下降序列長度)。關鍵在于第二問。以下A均表示新序列。
            設F[i]為以A[i]結尾的最長不下降序列長度(同樣,求法不用說了),G[i]為在A[i]不修改的前提下將A[0..i]轉變為不下降序列的最小修改量。首先求出F[i],然后在求G[i]時,枚舉上一個“不動點”(就是不修改的元素)A[j](顯然必須滿足A[j]<=A[i]且F[j]=F[i]-1),這樣最小修改量就是G[j]+(將A[j..i]轉變為不下降序列的最小修改量)。可以證明,A[j..i]的最優修改方案必然是將A[j+1..t]全部修改為A[j],A[t+1..i]全部修改為A[i],這里t是一個[j..i]范圍的值。問題就是如何求出最優的t?
            一開始,假設t=j,即把A[j+1..i-1]全部修改為A[i],計算出修改量,設為S。然后,由于A[j+1..i-1]之間的元素要么小于A[j],要么大于A[i](這個是顯然的囧),我們把小于A[j]的元素稱為“小數”,把大于A[i]的元素稱為“大數”,則當t取t0時,修改量為S-(A[i]-A[j])*(A[j+1..t0]中的“小數”個數減去“大數”個數)。這樣,只需掃描一下,求出使得(A[j+1..t0]中的“小數”個數減去“大數”個數)值最大的t0即可。
            當然還有一個問題,對于同一個i,滿足“A[j]<=A[i]且F[j]=F[i]-1”的元素個數可能有很多,如果一個一個枚舉,一個一個掃描,會很慢的囧……解決方法是,求出滿足這個條件的j中最小的一個,設為j0,然后把A[j0+1..i-1]中的所有“小數”和“大數”全部處理出來,然后用類似前綴和的方法就能搞了囧……當然,為了找到j0,需要建一個二分圖,邊為(F[i], i)。
            最后,為了方便,可以把A序列的左邊加一個-INF,右邊加一個+INF。最后總的時間復雜度,理論上為O(N2),但由于是隨機數據,所以遠遠達不到這個級別。

            代碼:
            #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 = 40010, INF = ~0U >> 2;
            struct edge {
                
            int a, b, pre, next;
            } E[MAXN 
            << 1];
            int n, m, A[MAXN], D[MAXN], F[MAXN], W[MAXN], res1;
            ll G[MAXN], res2;
            void init_d()
            {
                re(i, n) E[i].pre 
            = E[i].next = i; m = n;
            }
            void add_edge(int a, int b)
            {
                E[m].a 
            = a; E[m].b = b; E[m].pre = E[a].pre; E[m].next = a; E[a].pre = m; E[E[m].pre].next = m++;
            }
            void init()
            {
                scanf(
            "%d"&n);
                A[
            0= -INF; re1(i, n) {scanf("%d"&A[i]); A[i] -= i;} A[++n] = INF; n++;
            }
            void solve()
            {
                init_d(); F[
            0= 0; G[0= 0; D[0= -INF; add_edge(00); int len = 0, l, r, mid, x, maxw; ll sum, tmp;
                re2(i, 
            1, n) {
                    
            if (A[i] >= D[len]) D[F[i] = ++len] = A[i]; else {
                        l 
            = 0; r = len;
                        
            while (l < r) {
                            mid 
            = l + r + 1 >> 1;
                            
            if (A[i] >= D[mid]) l = mid; else r = mid - 1;
                        }
                        D[F[i] 
            = ++l] = A[i];
                    }
                    
            for (int p=E[F[i]-1].next; ; p=E[p].next) if (A[i] >= A[x = E[p].b]) break;
                    W[x] 
            = 0; re2(j, x+1, i) if (A[j] < A[i]) W[j] = W[j - 1+ 1else W[j] = W[j - 1- 1;
                    sum 
            = 0; maxw = -INF; G[i] = ~0Ull >> 2;
                    rre2(j, i, x) {
                        
            if (A[j] <= A[i] && F[j] == F[i] - 1) {
                            tmp 
            = G[j] + sum; if (tmp < G[i]) G[i] = tmp;
                            tmp 
            = G[j] + sum - (ll) (maxw - W[j]) * (A[i] - A[j]); if (tmp < G[i]) G[i] = tmp;
                        }
                        
            if (A[j] > A[i]) sum += A[j] - A[i]; else sum += A[i] - A[j];
                        
            if (W[j] > maxw) maxw = W[j];
                    }
                    add_edge(F[i], i);
                }
                res1 
            = n - F[n - 1- 1; res2 = G[n - 1];
            }
            void pri()
            {
                cout 
            << res1 << endl << res2 << endl;
            }
            int main()
            {
                init();
                solve();
                pri();
                
            return 0;
            }


            Feedback

            # re: 【AHOI2013復仇】兩道LIS模型題總結  回復  更多評論   

            2013-07-08 21:34 by nike0good
            我覺得可以用線段樹套Splay O(log^2n)求區間中位數

            # re: 【AHOI2013復仇】兩道LIS模型題總結  回復  更多評論   

            2015-03-09 17:14 by dreamATD
            [HAOI2006]數字序列里那個二分圖是干什么的?
            久久国产热这里只有精品| 亚洲国产高清精品线久久| 久久99热这里只频精品6| 亚洲国产成人久久笫一页| 香蕉99久久国产综合精品宅男自 | 九九99精品久久久久久| 香蕉久久夜色精品国产小说| 久久人搡人人玩人妻精品首页| 999久久久免费精品国产| 亚洲国产小视频精品久久久三级| 欧美日韩精品久久久久| 久久精品九九亚洲精品天堂| 久久综合亚洲色HEZYO社区| 国产精品久久久久久吹潮| 狠狠色综合网站久久久久久久高清 | 91精品国产9l久久久久| 无码人妻久久一区二区三区蜜桃| 久久99精品久久久久久hb无码| 国产亚洲色婷婷久久99精品91| 26uuu久久五月天| 色欲久久久天天天综合网精品| 亚州日韩精品专区久久久| AAA级久久久精品无码片| 欧美日韩精品久久久免费观看| 久久免费国产精品| 国产ww久久久久久久久久| 久久99热这里只有精品国产 | 久久人人爽人人爽人人片av麻烦| 欧美一级久久久久久久大| 狠狠色丁香婷婷久久综合不卡| 久久精品无码一区二区WWW| 国产精品乱码久久久久久软件| 久久精品国产第一区二区| 国产高清国内精品福利99久久| 东京热TOKYO综合久久精品| 日本久久久久亚洲中字幕| 国产一级做a爰片久久毛片| 精品久久久久久成人AV| 亚洲日韩中文无码久久| 久久久久国产精品嫩草影院| 亚州日韩精品专区久久久|